Cursor können nur innerhalb einer Transaktion deklariert werden:
test=# DECLARE mycursor CURSOR FOR SELECT * FROM t_passwd; ERROR: DECLARE CURSOR may only be used in transaction blocks
Mit Transaktionen werden wir uns noch in einem eigenen Kapitel beschäftigen - belassen wir es derweilen einmal dabei, dass wir vor einem Cursor ein BEGIN benötigen:
test=# BEGIN; BEGIN test=# DECLARE mycursor CURSOR FOR SELECT * FROM t_passwd; DECLARE CURSOR
Ist der Cursor erst einmal deklariert, können wir die Ergebnismenge mit Hilfe von FETCH abfragen:
test=# \h FETCH
Command: FETCH
Description: retrieve rows from a query using a cursor
Syntax:
FETCH [ direction { FROM | IN } ] cursorname
where direction can be empty or one of:
NEXT
PRIOR
FIRST
LAST
ABSOLUTE count
RELATIVE count
count
ALL
FORWARD
FORWARD count
FORWARD ALL
BACKWARD
BACKWARD count
BACKWARD ALL
Im einfachsten Fall wollen Sie schlichtweg einen Datensatz nach dem Anderen selektieren:
test=# FETCH NEXT FROM mycursor; account | passwd | uid | gid | gecos | directory | shell ---------+--------+-----+-----+-------+-----------+----------- root | x | 0 | 0 | root | /root | /bin/bash (1 row) test=# FETCH NEXT FROM mycursor; account | passwd | uid | gid | gecos | directory | shell ---------+--------+-----+-----+-------+-----------+--------------- bin | x | 1 | 1 | bin | /bin | /sbin/nologin (1 row)
Obwohl wir eine (möglicherweise) große Datenmenge durchlaufen, wird immer nur ein Datensatz auf einmal im Speicher gehalten, da die Datenbank das Ergebnis erst durch den Aufruf von FETCH berechnet.
Da das Abfragen von einem Datensatz eher ineffizient ist, kann man sich auch entscheiden, ein Bündel von Datensätzen auf einmal berechnen zu lassen. Das nächste Beispiel zeigt, wie drei Datensätze auf einmal erzeugt werden können:
test=# FETCH 3 FROM mycursor; account | passwd | uid | gid | gecos | directory | shell ---------+--------+-----+-----+--------+----------------+--------------- daemon | x | 2 | 2 | daemon | /sbin | /sbin/nologin adm | x | 3 | 4 | adm | /var/adm | /sbin/nologin lp | x | 4 | 7 | lp | /var/spool/lpd | /sbin/nologin (3 rows)
In der Regel fragt man Datensätze immer in Blöcken ab (beispielsweise 1000 Datensätze), da man so beträchtlichen Kommunikationsoverhead sparen kann. Die Größe dieser Datenpackages sollten Sie von Ihrer Applikation abhängig machen.
Cursor bieten auch die Möglichkeit, im Ergebnis zu springen. Sie können jederzeit auf vorangegangene Datensätze zurückgreifen:
test=# FETCH PRIOR FROM mycursor; account | passwd | uid | gid | gecos | directory | shell ---------+--------+-----+-----+-------+-----------+--------------- adm | x | 3 | 4 | adm | /var/adm | /sbin/nologin (1 row) test=# FETCH PRIOR FROM mycursor; account | passwd | uid | gid | gecos | directory | shell ---------+--------+-----+-----+--------+-----------+--------------- daemon | x | 2 | 2 | daemon | /sbin | /sbin/nologin (1 row)
Durch Verwendung des Schlüsselwortes PRIOR wird PostgreSQL aufgefordert, die vorangegangenen Datensätze zu durchlaufen.
Auch der Befehl MOVE dient zur Positionierung innerhalb des Cursors:
test=# \h MOVE
Command: MOVE
Description: position a cursor
Syntax:
MOVE [ direction { FROM | IN } ] cursorname
Wollen Sie einen Cursor wieder beenden, benötigen Sie den Befehl CLOSE:
test=# \h CLOSE Command: CLOSE Description: close a cursor Syntax: CLOSE name
Ansich reicht ein einfaches ROLLBACK respektive ein einfaches COMMIT, um einen Cursor zu beenden - wir empfehlen allerdings trotzdem, den Cursor korrekt zu schließen und anschließend die Transaktion zu beenden:
test=# CLOSE mycursor; CLOSE CURSOR test=# ROLLBACK; ROLLBACK