Oui. Vous pouvez placer la charge utile dans un bloc de code séparé avec gestion des exceptions :
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;
Il y a un exemple dans le manuel .
Mais je ne vois pas pourquoi vous attribuez tl2
premier (au lieu de tl1
), qui est susceptible de provoquer une exception à la première itération de la boucle. Vous pouvez éviter le problème a priori en utilisant un FOR
boucle
et au lieu d'un curseur explicite en combinaison avec une requête améliorée. Voir ci-dessous.
Aussi, votre UPDATE
n'a pas de WHERE
condition, qui est presque certainement erronée.
Et la fonction pgr_trsp()
semble pour le moins suspect. Passer du code sous forme de texte pue l'injection SQL. Cette réponse connexe sur dba.SE a une évaluation de SQLi dans plpgsql :
Fonctions Postgres vs requêtes préparées
Fonction auditée dans la question mise à jour
Réécrire votre code pour utiliser une logique basée sur des ensembles au lieu d'une boucle peut être plus propre et plus rapide. Pour commencer, vous pouvez simplifier quelque chose comme ceci (toujours avec une boucle, mais simplifiée) :
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;
En particulier, en utilisant ...
- Un
FOR
boucle avec curseur implicite au lieu d'un curseur explicite (peu maniable). - Fonctions de fenêtre.