给定一个类似于下面提供的示例的 pl/sql 过程,
const result = await connection.execute(
`BEGIN
:ret := no_func(:p1, :p2, :p3);
END;`,
{
p1: 'Chris',
p2: 'Jones',
p3: { dir: oracledb.BIND_OUT, type: oracledb.NUMBER },
ret: { dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 40 }
});
console.log(result.outBinds);
我的任务是不断调用该过程,直到没有记录为止。在这种情况下 result.outBinds 的响应是什么? (或者)我应该向循环添加什么条件以继续调用该过程,直到没有剩余?
非常感谢您的帮助。预先感谢。
让我们假设你有一个函数(没有副作用):
CREATE FUNCTION no_func(
p1 IN TABLE_NAME.C1%TYPE,
p2 IN TABLE_NAME.C2%TYPE,
p3 OUT TABLE_NAME.C3%TYPE
) RETURN TABLE_NAME.C4%TYPE
IS
v4 TABLE_NAME.C4%TYPE;
BEGIN
SELECT c3, c4
INTO p3, v4
FROM TABLE_NAME
WHERE c1 = p1
AND c2 = p2
FETCH FIRST ROW ONLY;
RETURN v4;
END;
/
和数据:
CREATE TABLE table_name (c1, c2, c3, c4) AS
SELECT 'Chris', 'Jones', 1, 2 FROM DUAL UNION ALL
SELECT 'Chris', 'Jones', 3, 4 FROM DUAL UNION ALL
SELECT 'Chris', 'Jones', 5, 6 FROM DUAL UNION ALL
SELECT 'Amber', 'Abbot', 7, 8 FROM DUAL;
然后如果你不断调用该函数:
DECLARE
p1 TABLE_NAME.C1%TYPE := 'Chris';
p2 TABLE_NAME.C2%TYPE := 'Jones';
p3 TABLE_NAME.C3%TYPE;
ret TABLE_NAME.C4%TYPE;
BEGIN
FOR i IN 1 .. 5 LOOP
ret := no_func(p1, p2, p3);
DBMS_OUTPUT.PUT_LINE(p3 || ', ' || ret);
END LOOP;
END;
/
它输出:
1, 2 1, 2 1, 2 1, 2 1, 2
(注意:如果您不断从 NodeJS 或任何其他客户端应用程序调用它,也会发生同样的情况。)
它不会获取下一条记录,它只是重复相同的第一条记录。除非你的函数有副作用或者依赖于存储在包中的某些外部状态或类似的东西(不要做其中任何一个),那么当你第一次调用该函数时,你可能会得到准确的结果与您第 nth 次调用它时的结果相同。 永远不会出现最初有一行然后没有剩余行的情况,因为函数将重复返回初始结果。
如果调用该函数并且没有找到行:
DECLARE
p1 TABLE_NAME.C1%TYPE := 'Bella';
p2 TABLE_NAME.C2%TYPE := 'Baron';
p3 TABLE_NAME.C3%TYPE;
ret TABLE_NAME.C4%TYPE;
BEGIN
ret := no_func(p1, p2, p3);
END;
/
然后你会得到异常:
ORA-01403: no data found
为此,请修改该函数,使其返回一个游标,然后从游标中读取所有匹配的行:
CREATE OR REPLACE FUNCTION no_func(
p1 IN TABLE_NAME.C1%TYPE,
p2 IN TABLE_NAME.C2%TYPE
) RETURN SYS_REFCURSOR
IS
cur SYS_REFCURSOR;
BEGIN
OPEN cur FOR
SELECT c3, c4
FROM TABLE_NAME
WHERE c1 = p1
AND c2 = p2;
RETURN cur;
END;
/
然后:
DECLARE
p1 TABLE_NAME.C1%TYPE := 'Chris';
p2 TABLE_NAME.C2%TYPE := 'Jones';
p3 TABLE_NAME.C3%TYPE;
p4 TABLE_NAME.C4%TYPE;
cur SYS_REFCURSOR;
BEGIN
cur := no_func(p1, p2);
LOOP
FETCH cur INTO p3, p4;
EXIT WHEN cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(p3 || ', ' || p4);
END LOOP;
END;
/
输出:
1, 2
3, 4
5, 6
您可以在 NodeJS 中执行类似操作(基于
REF CURSOR
绑定参数文档
) - 未经测试,因为我没有用于测试 NodeJS 代码的模式):
const result = await connection.execute(
`"BEGIN :cursor := no_func(:p1, :p2); END;`,
{
p1: "Chris",
p1: "Jones",
cursor: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
{
prefetchRows: 1000, // tune the internal getRow() data fetch performance
fetchArraySize: 1000
}
);
const resultSet = result.outBinds.cursor;
let row;
while ((row = await resultSet.getRow())) {
console.log(row);
}
await resultSet.close(); // always close the ResultSet