我正在尝试从 Oracle 复制一个具有以下代码片段的函数
OPEN pcursor FOR v_sql;
loop
fetch pcursor into
out_rec.XYZ
;
exit when pcursor%NOTFOUND;
INSERT INTO tab1 VALUES (out_rec.XYZ);
COMMIT;
pipe row(out_rec);
end loop;
EXCEPTION
WHEN OTHERS THEN
v_err_code := SQLCODE;
存储在 v_sql 中的查询存在一个问题,对于某些特定行值,它无法执行。 IE。在 SQL Developer 中,如果我执行查询,它会返回一些数据,但如果我将结果集获取到末尾或对其执行 count(*) 操作,则会失败,因为查询中的值之一返回错误数据。该错误无关紧要,但该函数的行为是它返回数据,直到到达错误点,然后完成。数据不完整(不会返回错误点之外的任何行),但数据确实存在。这是因为异常处理子句实际上并没有做任何事情(它吞噬了异常)
现在,当我尝试在 PostgreSQL 中复制此内容时,我遇到了几个问题。
CREATE OR REPLACE FUNCTION test_fn()
RETURNS table (t ret_data_type)
LANGUAGE plpgsql
AS $function$
...
for t in execute v_sql
loop
return next;
end loop;
exception when others then
raise notice 'error';
...
这对于没有错误的数据运行良好,但如果整个数据集中有任何错误,它就会失败并且不返回任何数据集。
我的问题是:有没有办法让 Postgresql 惰性地评估游标(一次几行)并继续返回数据,直到遇到错误?我正在查看文档,但没有看到任何内容。
看起来 PG 在循环之前获取了所有数据
它没有 - cursors 的要点之一是 not 正是这样做的。没有太多需要添加的@Frank Heikens'立即响应:如果您希望它继续,请将异常处理放在循环内。
db-fiddle 的演示
create table test as select '{"a":"b"}'::text t from generate_series(1,1e5);
insert into test select '{a:1}';--that's not a valid json/jsonb
insert into test select '{"a":"b"}'::text from generate_series(1,1e5);
create or replace function f()returns table(j jsonb) as $f$
declare rec record;
begin
for rec in select t from test loop
begin j:=rec.t; return next;
exception when others then raise notice '% ignored',rec.t;
end;
end loop;
end$f$language plpgsql;
create table test2 as select f();
NOTICE: {a:1} ignored
SELECT 200000
即使输入表中间有一个无效的
json
,处理/忽略循环内的异常也可以让您继续。
我确实尝试过,但没有帮助
处理或忽略错误后,在整个函数末尾处理
exception
将终止该函数。如果您将其向内移动到循环中并在 begin..exception..end
周围添加一个 return next
,这仍然不起作用,因为异常可能会在上面的 for t in execute v_sql
中的赋值中抛出。您必须显示您的实际代码才能确定。