1. Willkommen im Forum für alle Datenbanken! Registriere Dich kostenlos und diskutiere über DBs wie Mysql, MariaDB, Oracle, Sql-Server, Postgres, Access uvm
    Information ausblenden

Cursor oder Alternative

Dieses Thema im Forum "PostgreSQL" wurde erstellt von ukulele, 31 Mai 2019.

  1. ukulele

    ukulele Datenbank-Guru

    Bisher habe ich, um Datensätze zu durchlaufen und "zu verarbeiten", in MSSQL öfter mal zum Cursor gegriffen. Nützlich ist das vor allem wenn der Code zur Verarbeitung der Information hin und wieder mal auf unerwartete Fehler trifft und man wissen muss wo es scheitert.

    Ich hab so einen Beispielcode mal umgebaut aber PG verhält sich nicht wie von mir erwartet:
    Code:
    CREATE TEMP TABLE vLog(
           pk UUID NOT NULL,
           error VARCHAR(100) NOT NULL
           );
    
    DO $$
    DECLARE   vPK UUID;
           vData_html VARCHAR(10485760);
           vData_xml XML;
    BEGIN
       DECLARE   cursor3 CURSOR FOR
       SELECT   pk,
               data_html
       FROM   "public"."files"
       WHERE   data_xml IS NULL
       LIMIT 3;
    
       BEGIN
       OPEN cursor3;
       FETCH cursor3 INTO vPK,vData_html;
    
           INSERT INTO vLog(pk,error) VALUES(vPK,'test');
    
       CLOSE   cursor3;
       END;
    END $$;
    
    SELECT   pk,error
    FROM   vLog
    ORDER BY pk,error;
    
    DROP TABLE vLog;
    
    PG sagt mir erfolgreich ausgeführt. Ich bekomme aber keine Daten aus dem Select angezeigt.

    Man kann in PG wohl keinen Select oder Print oder etwas in der Form innerhalb des Cursors machen, wird mein Select aus dem selben Grund ignoriert? Gibt es eine sinnvollere Vorgehensweise?
     
  2. akretschmer

    akretschmer Datenbank-Guru

    liefert denn dein Select für den Cursor Daten?

    Code:
    test=*# \d files
                     Table "public.files"
      Column   |  Type   | Collation | Nullable | Default
    -----------+---------+-----------+----------+---------
     pk        | integer |           |          |
     data_html | text    |           |          |
     data_xml  | text    |           |          |
    
    test=*# select * from files;
     pk | data_html | data_xml
    ----+-----------+----------
      1 | a         |
      2 | a         |
      3 | a         |
      4 | a         |
    (4 rows)
    
    test=*# DO $$           
    DECLARE   vPK int;
           vData_html VARCHAR(10485760);
           vData_xml XML;
    BEGIN
       DECLARE   cursor3 CURSOR FOR
       SELECT   pk,
               data_html
       FROM   "public"."files"
       WHERE   data_xml IS NULL
       LIMIT 3;
    
       BEGIN
       OPEN cursor3;
       FETCH cursor3 INTO vPK,vData_html;
    
           INSERT INTO vLog(pk,error) VALUES(vPK,'test');
    
       CLOSE   cursor3;
       END;
    END $$;
    DO
    test=*# SELECT   pk,error
    FROM   vLog
    ORDER BY pk,error;
     pk | error
    ----+-------
      1 | test
      1 | test
    (2 rows)
    
    test=*#
    
    (2 mal ausgeführt, daher 2 Einträge)
     
  3. ukulele

    ukulele Datenbank-Guru

    Hmm ja, der Select im Cursor liefert 3 Datensätze. Wenn ich das in PGadmin 4 ausführe kommt als Messages:
    DROP TABLE Query returned successfully in 267 msec.
    und Data Output bleibt leer.
     
  4. castorp

    castorp Datenbank-Guru

    Wieso ein Cursor? Auch in SQL Server ist das normalerweise keine gute Idee.
    Das kann man doch mit einem einfach INSERT INTO ... SELECT ... erledigen.

    Das Äquivalent zu PRINT wäre ein RAISE NOTICE in PL/pgSQL
     
    akretschmer gefällt das.
  5. ukulele

    ukulele Datenbank-Guru

    Der Cursor sorgt nur dafür das die Datensätze nach einander, einzeln abgearbeitet werden. Bei einem Fehler für einen Datensatz wird die ID + Fehlermeldung geloggt und er macht den Rest dennoch weiter. Wenn bei INSERT INTO irgend ein Teil meines Codes mist erzeugt bekomme ich zwar einen Fehler aber eben nicht die Info in welchen Ausgangsdatensatz.
     
  6. ukulele

    ukulele Datenbank-Guru

    Mit RAISE NOTICE bekomme ich eine UUID ausgespuckt, fehlt da irgendwie noch ein FETCH NEXT ... INTO ... im Cursor?

    PS: Scheinbar ist hier PGadmin 4 schuld. akretschmer womit hast du das laufen lassen?
     
  7. akretschmer

    akretschmer Datenbank-Guru

    wenn du alle in die Tabelle einfügen willst: ja, dann brauchst Du da eine Schleife.
     
  8. castorp

    castorp Datenbank-Guru

    Das ist eine falsche Annahme. Das läuft alles in einer Transaktion. Und die Definition einer Transaktion ist nunmal, dass alles erfolgreich ist, oder nichts.
    Wenn Du dieses Verhalten willst, musst Du mit Savepoints arbeiten
     
  9. ukulele

    ukulele Datenbank-Guru

    Okay stimmt, die Transaktion darf natürlich nicht scheitern. Aber ich kann schon, Datensatz für Datensatz anhand eigener Kriterien, entscheiden ob die Daten valide sind. In MSSQL gibt es z.B. try_convert(), damit kann ich testen ob es sich grundsätzlich um valides XML handelt. Wenn nicht schreibe ich in meine Log-Tabelle und gucke mir die Datensätze händisch an.
     
  10. castorp

    castorp Datenbank-Guru

    Im Grunde macht man das via savepoints in Postgres. try_convert() könnte man mit einer eigenen PL/pgSQL Funktion simulieren die einen CAST versucht, die Exception fängt und dann einfach NULL zurückgibt. Exception handling ist aber teuer, und damit wäre die Funktion relativ langsam (ob das ein Problem ist oder nicht kann ich nicht beurteilen). Wenn es nur um Zahlen geht, würde ich vermutlich eher zu einem Test via CASE und einem regex greifen
     
  11. akretschmer

    akretschmer Datenbank-Guru

    psql
     
  12. ukulele

    ukulele Datenbank-Guru

    try_convert() war auch erstmal ein Beispiel, es gibt noch andere Validierungen, auch mit LIKE bzw. regexp. Bei dem Cursor (oder Loop oder was auch immer ich am Ende nehme) geht es nur darum alle Datensätze zu durchlaufen, für jeden Datensatz mehrere Prüfungen anzustoßen und ggf. fehlerhafte Datensätze zu identifizieren das ich sie mir angucken kann.
     
Die Seite wird geladen...

Diese Seite empfehlen

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies.
    Information ausblenden