PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Kann ich EXCEPTIONs in einer FOR-SCHLEIFE verwenden, um eine Fortsetzung bei einem Fehler zu erzwingen?

Ja. Sie können die Nutzdaten in einem separaten Codeblock mit Ausnahmebehandlung ablegen:

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;

Es gibt ein Beispiel im Handbuch .

Aber ich verstehe nicht, warum Sie tl2 zuweisen zuerst (statt tl1 ), was zwangsläufig bei der ersten Iteration der Schleife eine Ausnahme verursacht. Sie können das Problem a priori vermeiden, indem Sie ein FOR Schleife und anstelle eines expliziten Cursors in Kombination mit einer erweiterten Abfrage. Siehe unten.

Außerdem Ihr UPDATE hat kein WHERE Bedingung, die mit ziemlicher Sicherheit falsch ist.

Und die Funktion pgr_trsp() sieht gelinde gesagt verdächtig aus. Das Übergeben von Code als Text riecht nach SQL-Injection. Diese verwandte Antwort auf dba.SE enthält eine Bewertung von SQLi in plpgsql:
Postgres-Funktionen vs. vorbereitete Abfragen

Geprüfte Funktion in aktualisierter Frage

Das Umschreiben Ihres Codes zur Verwendung von mengenbasierter Logik anstelle von Schleifen könnte sauberer und schneller sein. Für den Anfang können Sie so etwas vereinfachen (immer noch mit einer Schleife, aber vereinfacht):

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;

Insbesondere mit ...