1

这是我想做的一个例子,问题是我不明白如何收集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);
              }
            });
        }
4

1 回答 1

0

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

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

由于它们已编写(并创建了博客文章),node-oracledb 代码已得到改进,您可能会发现直接获取,甚至调用 getRow() 单数已经足够快,因此可以简化管道示例,如果那样的话对你来说是个问题。

我还建议现在使用 async/await 编程风格,因为这通常更容易正确处理。

于 2019-02-21T04:54:20.863 回答