这是我要执行的示例,问题是我不了解如何在过程中收集所有输出DBMS_OUTPUT.PUT_LINE

有两种方法可以做到,我不知道是否有适合我的方法。

该示例摘自以下链接。


  名称:dbmsoutput.js
  
  描述:
             显示在node-oracledb中显示PL / SQL DBMS_OUTPUT的两种方法。
              第二种方法取决于以下PL / SQL对象:
                创建或替换类型dorow作为varchar2(32767)的表;
  https://blogs.oracle.com/opal/using-dbmsoutput-with-nodejs-and-node-oracledb


        'use strict';
        var async = require('async');
        var oracledb = require('oracledb');
        var dbconfig = require('./dbconfig.js');
        oracledb.createPool(
          dbconfig,
            function(err, pool) {
                if (err)
                console.error(err.message)
                else
                doit(pool);
            });
            var doit = function(pool) {
            async.waterfall(
            [
              function(cb) {
                pool.getConnection(cb);
              },
              // Tell the DB to buffer DBMS_OUTPUT
              enableDbmsOutput,
              // Method 1: Fetch a line of DBMS_OUTPUT at a time
              createDbmsOutput,
              fetchDbmsOutputLine,
              // Method 2: Use a pipelined query to get DBMS_OUTPUT
              //createDbmsOutput,
              function(conn, cb) {
                executeSql(
                  conn,
                  "begin NoticiasMasVistas(2018); end;", [], { resultSet: true}, cb);
              },
              printQueryResults
            ],
            function (err, conn) {
            if (err) { console.error("In waterfall error cb: ==>", err, "<=="); }
            conn.release(
                function (err) {
                    if (err) console.error(err.message);
                    let pool = oracledb.getPool();
                    pool.close(10);
                });
            }
          )
        };
        var enableDbmsOutput = function (conn, cb) {
          conn.execute(
            "begin dbms_output.enable(null); end;",
            function(err) { return cb(err, conn) });
        }
        var createDbmsOutput = function (conn, cb) {
          conn.execute(
            `CREATE OR REPLACE PROCEDURE NoticiasMasVistas(p_anio NUMBER) IS
                v_IdPer ej_periodico.IdPer%TYPE;
                v_numNoticias INTEGER;
              CURSOR cPeriodico IS
                SELECT p.Nombre, p.IdPer FROM ej_periodico p;

              CURSOR cNoticiasMes IS
                SELECT EXTRACT(MONTH FROM n.FechaPub) mes, n.Titular, n.NumVisitas
                  FROM ej_noticia n
                  WHERE EXTRACT(YEAR FROM n.FechaPub) = p_anio
                  AND n.IdPer = v_IdPer
                  AND n.NumVisitas = (SELECT MAX(n2.NumVisitas)
                    FROM ej_noticia n2
                    WHERE EXTRACT(YEAR FROM n2.FechaPub) = p_anio
                    AND n2.IdPer = n.IdPer
                    AND EXTRACT(MONTH FROM n2.FechaPub) =  EXTRACT(MONTH FROM n.FechaPub));
              BEGIN
              DBMS_OUTPUT.PUT_LINE('NOTICIAS MAS VISITADAS ' || p_anio);
              FOR rPeriodico IN cPeriodico LOOP
                DBMS_OUTPUT.PUT_LINE('Perdiodico : ' || rPeriodico.Nombre);
                v_IdPer := rPeriodico.IdPer;
                v_numNoticias := 0;
                FOR rNoticiasMes IN cNoticiasMes LOOP
                  v_numNoticias := v_numNoticias + 1;
                  DBMS_OUTPUT.PUT_LINE('  Mes: ' || TO_CHAR(rNoticiasMes.mes,'99') ||
                    ': ' || RPAD(rNoticiasMes.Titular,70));
                  DBMS_OUTPUT.PUT_LINE('            ' || rNoticiasMes.numVisitas || ' Visitas.');
                END LOOP;
                  IF v_numNoticias = 0 THEN
                  DBMS_OUTPUT.PUT_LINE('  No se han publicado noticias durante 2018');
                  END IF;
              END LOOP;
            END;`,
            function(err) { return cb(err, conn) });
        }
        var fetchDbmsOutputLine = function (conn, cb) {
          conn.execute(
            "begin NoticiasMasVistas(2018); end;",
            {},
            function(err, result) {
              if (err) {
                return cb(err, conn);
              } else if (result.outBinds.st == 1) {
                return cb(null, conn);  // no more output
              } else {
                console.log(result.outBinds.ln);
                return fetchDbmsOutputLine(conn, cb);
              }
            });
          }
        var executeSql = function (conn, sql, binds, options, cb) {
          conn.execute(
            sql, binds, options,
            function (err, result) {
              if (err)
                cb(err, conn)
              else
                cb(null, conn, result);
            });
        }
        var printQueryResults = function(conn, result, cb) {
          if (result.resultSet) {
            fetchOneRowFromRS(conn, result.resultSet, cb);
          } else if (result.rows && result.rows.length > 0) {
            console.log(result.rows);
            return cb(null, conn);
          } else {
            console.log("No results");
            return cb(null, conn);
          }
        }
        function fetchOneRowFromRS(conn, resultSet, cb) {
          resultSet.getRow(  // note: getRows would be more efficient
            function (err, row) {
              if (err) {
                cb(err, conn);
              } else if (row) {
                console.log(row);
                fetchOneRowFromRS(conn, resultSet, cb);
              } else {
                cb(null, conn);
              }
            });
        }

最佳答案

node-oracledb存储库中有两个可运行的示例:


dbmsoutputgetline.js
dbmsoutputpipe.js


第一个为每行输出调用DBMS_OUTPUT.GET_LINE(),因此它可能比管道示例慢,但是它更简单,因此对于快速测试或输出行数少的地方可能很方便。管道示例可以利用优化的查询代码来一次从数据库中获取多个记录。

自从编写了它们(并创建了博客文章)以来,node-oracledb代码已经成为improved,您可能会发现直接提取甚至单单调用getRow()都足够快,因此可以简化管道示例,如果那是您的问题。

我还建议立即使用异步/等待编程风格,因为这样做通常更容易实现。

09-26 12:06