Pet*_*sos 0 postgresql loops exception-handling plpgsql
发生(可预测或不可预测)错误时,是否可以在FOR循环中使用EXCEPTIONs强制继续执行?这是一个片段:
FOR temp_rec IN tlcursor LOOP
tl2 := temp_rec; --the location to be updated
--Do the Routing and UPDATE the taxilocs row.
UPDATE taxilocs20120113
SET route = pgr_trsp (
'SELECT * FROM th_2po_4pgr',
tl1.map_id, tl1.map_pos, tl2.map_id, tl2.map_pos, false, true);
tl1 := tl2;
END LOOP;
Run Code Online (Sandbox Code Playgroud)
一个例子是,在第一次迭代期间,tl1未分配。另一个可能是该函数pge_trsp()没有提供结果。如果在执行过程中发生任何这种情况,是否可以强制循环继续?
更新!!
这是我最新的代码:
CREATE OR REPLACE FUNCTION fm_seqrouting() RETURNS integer AS $$
--Declarations
DECLARE
tlcursor SCROLL CURSOR FOR SELECT
oid,
veh_id,
date_time AS dt,
th_2po_4pgr_id AS map_id,
th_2po_4pgr_position AS map_pos FROM testlocs
ORDER BY veh_id, dt;
tl1 RECORD;
tl2 RECORD;
i integer;
BEGIN
--CODE to calculate routes and update table
i := 0;
FOR temp_rec IN tlcursor LOOP
tl2 := temp_rec; --the location to be updated
BEGIN --Nest the UPDATE in a block to esace errors
--Do the Routing and UPDATE the taxilocs row.
UPDATE taxilocs20120113
SET "pgRoute" = pgr_trsp (
'SELECT * FROM th_2po_4pgr',
tl1.map_id, tl1.map_pos, tl2.map_id, tl2.map_pos, false, true)
WHERE taxilocs20120113.oid = tl2.oid;
i := i + 1;
EXCEPTION
WHEN SQLSTATE '55000' THEN NULL;
WHEN SQLSTATE 'XX000' THEN NULL;
WHEN SQLSTATE '38001' THEN NULL;
END;
tl1 := tl2;
END LOOP;
RETURN i;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
事实是,这在内存方面非常紧张,但是我是编程新手(我什至都不是程序员)。任何提示表示赞赏!
是。您可以将有效负载放在带有异常处理的单独代码块中:
FOR temp_rec IN tlcursor LOOP
tl2 := temp_rec; --the location to be updated
--Do the Routing and UPDATE the taxilocs row.
BEGIN
UPDATE taxilocs20120113
SET route = pgr_trsp (
'SELECT * FROM th_2po_4pgr',
tl1.map_id, tl1.map_pos, tl2.map_id, tl2.map_pos, false, true);
EXCEPTION WHEN OTHERS THEN
-- keep looping
END;
tl1 := tl2;
END LOOP;
Run Code Online (Sandbox Code Playgroud)
但是我看不到为什么tl2要先分配(而不是tl1),这肯定会在循环的第一次迭代时导致异常。您可以通过使用FOR循环而不是将显式游标与增强型查询结合使用来避免先验问题。见下文。
另外,您UPDATE没有WHERE条件,这几乎肯定是错误的。
pgr_trsp()至少可以说该功能看起来很可疑。将代码作为SQL注入的文本传递。dba.SE上的此相关答案对plpgsql中的SQLi进行了评估:
Postgres函数与准备好的查询
使用基于集合的逻辑而不是循环来重写代码可能更干净,更快。对于初学者,您可以简化为以下内容(仍然带有循环,但已简化):
CREATE OR REPLACE FUNCTION fm_seqrouting()
RETURNS integer AS
$func$
DECLARE
r record;
BEGIN
FOR r IN
SELECT oid -- no proper pk?
,th_2po_4pgr_id AS map_id1
,th_2po_4pgr_position AS map_pos1
,lead(th_2po_4pgr_id) OVER w AS map_id2
,lead(th_2po_4pgr_position) OVER w AS map_pos2
,count(*) OVER () AS ct
FROM testlocs
WINDOW w AS (ORDER BY veh_id, dt)
ORDER BY veh_id, dt -- you don't need order by columns in result
LOOP
BEGIN -- may be unnecessary
UPDATE taxilocs20120113
SET "pgRoute" = pgr_trsp(
'SELECT * FROM th_2po_4pgr'
,r.last_map_id, r.last_map_pos, r.map_id, r.map_pos, false, true)
WHERE taxilocs20120113.oid = r.oid;
EXCEPTION
WHEN SQLSTATE '55000' THEN NULL;
WHEN SQLSTATE 'XX000' THEN NULL;
WHEN SQLSTATE '38001' THEN NULL;
END;
END LOOP;
RETURN r.ct;
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
特别是使用...
FOR与隐式游标循环而不是一个(笨重)显式游标。