| PLSQL-Cursor: Das Cursorkonzept |
|
|
| Donnerstag, 16. Oktober 2008 um 15:04 | ||||
|
Cursor werden benutzt, um Daten aus ORACLE-Tabellen in ein PL/SQL-Programm zu übernehmen und damit sehr luxuriös zu arbeiten. Für jede Ausführung eines SQL-Befehls wird Memory allokiert. PL/SQL erlaubt es nun, dieses Memory zu benennen. Diese wird auch Context-Area oder Cursor genannt. Eine Cursor-Variable ist ähnlich wie ein Zeiger, der in die Context Area zeigt. Wenn eine Cursor-Variable deklariert wird, erhält man einen Pointer, der erstmal nirgendwo hinzeigt. Erst, wenn der Cursor geöffnet wird, wird Memory allokiert und die Cursor-Variable zeigt auf den Cursor. Wenn der Cursor geschlossen wird, wird Speicher freigegeben, die Cursor-Variable ist dann nicht mehr nutzbar. Explizite CursorORACLE unterscheidet zwischen impliziten und expliziten Cursor. Die impliziten werden quasi durch Ausführung von SQL-Kommandos automatisch erzeugt und erlauben nur eine geringe Kontrolle des Speicherbereichs. Deklaration eines CursorExplizite Cursor werden benutzt, wenn eine Query mehr als einen Datensatz zurückliefert und werden im DECLARE-Teil bekannt gemacht. DECLARE Die Verarbeitung von mehreren Ergebnis-Zeilen ist ganz ähnlich zur Arbeit mit Dateien. Um Dateiinhalte zu verarbeiten, muss das File geöffnet werden, Datensatz für Datensatz verarbeitet werden und im Anschluss die Datei wieder geschlossen werden. Öffnen eines CursorDECLARE Wenn ein Cursor geöffnet wird, wird das dahinterliegende SELECT-Kommando ausgeführt und die zu liefernden Datensätze ermittelt. Fetchen aus dem CursorUm eine Zeile aus einem Cursor zu holen, müssen wir die Zeile aus dem Cursor in eine entsprechende PL/SQL-Variable übernehmen. Der Pointer zeigt im Anschluss automatisch auf den nächsten Datensatz, so daß ein weiteres Fetch die zweite Zeile liefert usw. Sind keine weiteren Datensätze im Cursor enthalten, liefert ein Fetch nicht etwa eine Exception, sondern NULL. DECLARE Schliessen des CursorsNachdem die gewünschten Datensätze verarbeitet sind, muß der Cursor wieder geschlossen werden. DECLARE Auch wenn bei anonymen Blöcken Cursor automatisch geschlossen werden, sollte man dennoch stets explizit schliessen. Das ist zum einen gute Programmierpraxis, zum anderen gibt es auch Situationen, in denen ein Cursor versehentlich geöffnet bleibt und damit unnötig Speicher verbraucht (z.B. beim Einsatz in Packages). Ein Cursor liefert also sequentiell die mit dem SELECT ermittelten Datensätze. Ein Fetch liefert stets den nächsten anstehenden Satz, ein Hin- und Herspringen (ala “liefer mir den vorletzten erneut”) geht nicht (vergleichbar mit einer einfach verketteten Liste). Nachdem der Cursor geschlossen ist, ist ein Fetch nicht mehr möglich. Wenn der Cursor erneut geöffnet wird, wird auch das Select wieder ausgeführt und das Spiel kann von neuem beginnen. Cursor AttributeJeder explizite Cursor hat vier Attribute, die an den Cursornamen “angehängt” werden können, um weitere Informationen zu erhalten.
Folgendes Beispiel gibt alle Mitarbeiternamen am Bildschirm aus. set serveroutput on Die FOR-CURSOR-LOOPSie wurde schonmal kurz bei den Schleifenkonstrukten erläutert, macht hier aber erst Sinn: Diese Form der Schleife terminiert automatisch, wenn keine weiteren Datensätze mehr gefetcht werden. Der Cursor wird implizit geöffnet und geschlossen. Auch eine passende Record-Variable wird implizit deklariert. Damit das wird vorhergehendes Beispiel deutlich schlanker. set serveroutput on Daten ändern mit einem CursorDatenveränderungen sind auch mit Hilfe von Cursors möglich. Die Cursor-Deklaration selbst enthält allerdings weiterhin das SELECT-Kommando, nur der Zusatz FOR UPDATE ist neu, und sorgt für ein Sperren der Datensätze bereits beim Lesen. DECLARE Eine explizite Bedingung mit Primärschlüssel ist also nicht notwendig.
|
||||
| Aktualisiert ( Mittwoch, 15. April 2009 um 16:43 ) | ||||


Kommentare
habs sofort korrigiert. Zitieren
Ich habe die Codebeispiele ausprobiert.
Musste allerdings etwas ändern:
…
— OPEN Cursor emp_cur
OPEN emp_cur;
…
ich habe bei der ersten Version einen Fehler bekommen:
Encountered the symbol "EMP_CUR" when expecting one of the following:
. ( % ; for
The symbol "." was substituted for "EMP_CUR" to continue.
MFG
Andreas Zitieren
ein FOR UPDATE mit GROUP BY ist unzulässig.
Bei einem FOR UPDATE soll ja der zu lesende Datensatz für eine folgende Veränderung gesperrt werden. Wenn Du aber gruppierst, sind die gelesenen Datensätze ja ein Aggregat und können nicht gesperrt werden. Stell Dir vor, es gibt in Deiner EMP Tabelle zwei Datensätze, die den Namen "SCOTT" haben. Welcher sollte gesperrt werden?
Also: Entweder FOR UPDATE weglassen (und im UPDATE mit WHERE ename = myrec.ename arbeiten). Oder auf GROUP BY verzichten (in Deinem Beispiel macht es ja eh keinen Sinn. Wenn Du doppelte Datensätze verhindern willst, nutze DISTINCT).
Liebe Grüße
Martin Zitieren
Ich habe so etwas ausprobiert:
DECLARE
CURSOR emp_cur IS SELECT ename FROM EMP GROUP BY ename FOR UPDATE;
BEGIN
FOR myrec IN emp_cur LOOP
dbms_output.put_line(myrec.ename);
UPDATE emp set sal = sal + 100 WHERE CURRENT OF emp_cur;
END LOOP;
END;
und da kriege ich nur:
PL/SQL: ORA-01786: FOR UPDATE of this query expression is not allowed
Alle Kommentare dieses Beitrages als RSS-Feed.