sql - 在一个包中使用多个过程和多个游标
问题描述
我创建了一个包含两个过程和两个游标的包,但是在执行过程时,它执行成功,但同一记录执行了多次并发生缓冲区溢出。
我还尝试从光标中删除循环,但对于 1 条记录会很好,而对于多条记录,它不会按预期工作。
预期的
我只需要从我要多次执行同一记录的过程中删除同一记录的多次执行
对于单个过程和单个游标,它工作正常,但对于多个游标和多个过程,我在这里遇到问题,这也导致缓冲区溢出,我需要不同的记录
有没有其他方法可以解决问题?
CREATE OR REPLACE PACKAGE test.report AS
PROCEDURE distribution (
code_in IN user.test.code%TYPE,
fromdate date,
todate date
);
PROCEDURE tdvalue (
id IN user.test.custid%TYPE
);
END report;
/
包体
CREATE OR REPLACE PACKAGE BODY test.report as
----------VARIABLE DECLARATION----------------
code_in user.test.code%TYPE;
custidin user.test.custid%TYPE;
fromdate DATE;
todate DATE;
diff number(17,2);
---------------CURSOR DECLARATION--------------
CURSOR td_data(code_in user.test.code%TYPE,
fromdate date,
todate date
) IS
( SELECT
test.code,
COUNT(test.code) AS count,
SUM(test2.Deposit_amount) AS total,
test.currency
FROM
user.test2
JOIN user.test ON test2.acid = test.acid
WHERE
user.test2.open_effective_date BETWEEN TO_DATE(fromdate, 'dd-mm-yyyy') AND TO_DATE(todate, 'dd-mm-yyyy')
and
user.test.code = code_in
GROUP BY
test.code,test.currency
);
td__data td_data%rowtype;
CURSOR C_DATA(custidin user.test.custid%TYPE) IS SELECT
test.custid,
test2.id,
TO_DATE(test2.initial_date, 'dd-mm-yyyy') - TO_DATE(test2.end_date, 'dd-mm-yyyy') AS noofdays,
round(((test2.deposit_amount *((TO_DATE(test2.initial_date, 'dd-mm-yyyy') - TO_DATE(test2.end_date, 'dd-mm-yyyy'
)) / 365) * test4.interest_rate) / 100), 2) + test2.deposit_amount AS calculated_amount,
SUM(test.flow_amt) + test2.deposit_amount AS system_amount
FROM
user.test
JOIN user.test2 ON test3.entity_id = test2.id
WHERE
test.custid = custidin
GROUP BY
test.custid,
test2.id;
c__data c_data%ROWTYPE;
PROCEDURE distribution
(
code_in IN user.test.code%TYPE,
fromdate in date,
todate in date
)
AS
BEGIN
OPEN td_data(code_in,fromdate,todate);
loop
FETCH td_data INTO td__data;
dbms_output.put_line(td__data.code
|| ' '
|| td__data.count
|| ' '
||td__data.currency
||' '
||td__data.total
);
end loop;
CLOSE td_data;
END distribution;
PROCEDURE tdvalue (
custidin IN user.test.custid%TYPE
)
AS
BEGIN
open c_data(custidin);
fetch c_data into c__data;
loop
diff:= c__data.calculated_amount- c__data.system_amount;
dbms_output.put_line(c__data.custid
|| ' '
|| c__data.noofdays
|| ' '
|| c__data.end_date
|| ' '
|| c__data.initial_date
|| ' '
|| c__data.calculated_amount
||' '
||diff
);
end loop;
close c_data;
END tdvalue;
END report;
/
跑步
ALTER SESSION set nls_date_format='dd-mm-yyyy';
SET SERVEROUTPUT ON;
EXEC REPORT.DISTRIBUTION('872328','01-02-2016','08-02-2019');
/
EXEC REPORT.tdvalue('S9292879383SS53');
解决方案
当通过 DBMS_OUTPUT 显示的总字节数超过服务器输出缓冲区的大小时,会发生缓冲区溢出 - ORU-10027。默认只有 20000 字节(谁知道为什么?)。由于您启用serveroutput
. 显然,一条记录少于 2000 条,只有在运行多条记录时才会达到该限制。
要解决这个问题,试试这个
SET SERVEROUTPUT ON size unlimited
它实际上不是无限的,但上限是 PGA 限制(会话内存),您真的不应该使用 DBMS_OUTPUT 达到该限制。除了其他任何东西,谁会阅读所有这些内容?
因此,正如@piezol 指出的那样,您的代码的另一个问题是您的循环没有退出点。您应该测试 FETCH 是否实际获取任何内容,如果没有则退出:
loop
FETCH td_data INTO td__data;
exit when td_data%notfound;
dbms_output.put_line(td__data.code
|| ' '
|| td__data.count
|| ' '
||td__data.currency
||' '
||td__data.total
);
end loop;
记住这样做只是隐式游标和循环游标优于显式游标的原因之一。
第二个游标循环更糟糕,因为它不仅没有存在点,而且 fetch在循环之外。这就是为什么您为同一记录重复输出的原因。
所以让我们重写这个......
open c_data(custidin);
fetch c_data into c__data; -- should be inside
loop
diff:= c__data.calculated_amount- c__data.system_amount;
…作为循环的光标:
PROCEDURE tdvalue (
custidin IN user.test.custid%TYPE
)
AS
BEGIN
for c__data in c_data(custidin)
loop
diff:= c__data.calculated_amount- c__data.system_amount;
dbms_output.put_line(c__data.custid
|| ' '
|| c__data.noofdays
|| ' '
|| c__data.end_date
|| ' '
|| c__data.initial_date
|| ' '
|| c__data.calculated_amount
||' '
||diff
);
end loop;
END tdvalue;
无需 OPEN、CLOSE 或 FETCH,也无需检查游标何时耗尽。
推荐阅读
- ios - 用“const 常量”声明变量的目的是什么?
- python - 在 Django 中迁移和创建超级用户后出现“没有这样的表:accounts_user”
- html - 如何用我的图标来满足页面的宽度?
- python - Python 多层网页抓取
- c++ - sf::Text 不显示?
- mariadb - 无法在 Mariadb 中使用函数调用添加约束检查
- javascript - 条码阅读器扫描的不可读条码
- nginx - Nginx 代理覆盖默认 HTML 文件
- r - 如何正确地将带引号的字符串作为 URL 输入的一部分传递给 httr:GET()?
- python-2.7 - 如何使用 python 2.7 将图像上传到谷歌云存储