| Arbeiten mit PL/SQL-Tabellen |
|
|
| Donnerstag, 16. Oktober 2008 um 15:00 | ||||
|
Die Arbeit mit PL/SQL scheint auf den ersten Blick kompliziert. Tatsächlich steht aber ein mächtiges Konzept dahinter, um mehrere Werte auf einmal zu bearbeiten. Wie Records werden auch PL/SQL Tabellen in zwei Schritten erzeugt. Erst muss die Tabellenstruktur deklariert werden mit Hilfe des TYPE Statements. Im zweiten Schritt muß eine Variable des eben angelegten Tabellentypen deklariert, bzw. instanziiert werden. Die Deklaration erfolgt mit
Dies erzeugt einen Tabellentypen, der 20stellige VARCHAR2-Werte aufnimmt. Das NOT NULL ist optional. Die Datentypen in einem Tabellentypen können alle skalaren Typen sein, aber auch Records (womöglich ein Record, dessen Feldkomponente wieder eine Tabelle ist? Damit läßt sich ganz schön was anstellen…). Um eine Variable des Typen zu instanziieren, nutzen wir
ACHTUNG! Seit der ORACLE-Version 9i ist es auch möglich, als Index-Kriterium Zeichenketten zu verwenden, so daß Sie mit Hilfe eines Strings auf eine Zeile der Tabelle zugreifen können (deshalb spricht man jetzt auch von associative arrays).
Weiterhin wichtig ist, dass Sie die Indizierungsform durchaus weglassen können, also z.B.
Dann handelt es sich aber nicht mehr um eine PL/SQL-Tabelle, sondern um eine nested table, die sich an bestimmten Stellen anders als eine PL/SQL-Tabelle verhält. Zeilen in PL/SQL TabellenWir erinnern uns, dass wir auf Zeilen in einer PL/SQL Tabelle mit Hilfe eines Index zugreifen. Die Syntax hierzu sieht wie folgt aus:
Der Die folgenden Beispiele sind allesamt zulÄssig. Wir nutzen automatische Typkonvertierung, Zahlen mit Nachkommaanteil werden gerundet.
Auf die gleiche Art und Weise können wir auch wieder aus einer Tabelle lesen. Was passiert aber, wenn eine referenzierte Zeile nicht existiert? Eine Zeile existiert erst, wenn ihr ein Wert zugewiesen wurde (Dieser Wert kann natürlich auch NULL sein). Wenn Sie versuchen, eine Zeile anzusprechen, die nicht existiert, erhalten Sie eine NO_DATA_FOUND Ausnahme. PL/SQL Tabellen füllen und leerenEs gibt drei verschiedene Arten, PL/SQL Tabellen zu füllen.
Direkte Zuweisung meint die Form, die wir zuvor genutzt haben, also:
Die iterative Zuweisung erfolgt z.B. in Form einer Schleife. Meist wird hier wohl die FOR-CURSOR-LOOP genutzt, um die Daten aus einer SQL Tabelle in eine PL/SQL Tabelle zu übernehmen.
Eine wesentlich schnellere Form ist das sogenannte BULK COLLECT:
Aggregierte Zuweisung meint die Zuweisung einer gesamten Tabelle an eine andere Tabelle. Diese muß typkompatibel sein. So wie bei Records ist das Vergleichen zweier Tabellen auf diese Art nicht möglich, hier muß Element für Element verglichen werden.
Es ist nicht möglich, alle Zeilen einer Tabelle zu entfernen oder gar zu “droppen”. Zwar können wir den einzelnen Zeilen einer Tabelle den Wert NULL zuweisen, aber die Zeile existiert weiter, eben gefüllt mit dem NULL Wert. Um eine Tabelle zu leeren und den verwendeten Speicher freizugeben, können wir einen Trick anwenden:
Seit PL/SQL Version 2.3 kann aber auch das DELETE Statement genutzt werden. PL/SQL TabellenfunktionenEs gibt für die Arbeit mit PL/SQL Tabellen eine Reihe vordefinierter Prozeduren und Funktionen:
Damit erhalten wir eine Reihe von Informationen über die referenzierte Tabelle, mit der Ausnahme der DELETE Anweisung, die eine Zeile aus einer Tabelle löscht. Die DELETE AnweisungDie DELETE Anweisung tut genau das, was wir erwarten: Sie löscht Zeilen in PL/SQL Tabellen. Die Syntax ist allerdings eine andere als in SQL:
Die COUNT FunktionAuch diese Funktion ist recht einfach zu merken. Sie liefert die Anzahl Werte in der PL/SQL Tabelle zurück. Zeilen, denen kein Wert zugeordnet ist, werden nicht mitgezählt. Sind keine Zeilen in der Tabelle, liefert COUNT die Zahl 0 zurück.
Die FIRST FunktionDie FIRST Funktion liefert den kleinsten Index zurück, an dem ein Wert eingetragen wurde. Sind keine Elemente (Zeilen) in der PL/SQL Tabelle, liefert FIRST den Wert NULL zurück.
Die NEXT FunktionDie NEXT Funktion liefert für einen gegebenen Indexwert den nächstgrößeren zurück, an dem ein Wert eingetragen ist. Sie ist sehr nützlich, weil wir ja erwähnt haben, dass eine PL/SQL Tabelle lückenhaft sein kann, die Zeilen also nicht hintereinanderliegen müssen. Das nächste Element nach Zeile 10 kann also 1000 sein. Wenn es keine Werte mehr hinter dem übergebenen Indexwert gibt, liefert NEXT den Wert NULL.
Im obigen Beispiel erhält die Variable next_value den Wert 5. Die LAST FunktionSie ist das genaue Gegenteil der FIRST Funktion, liefert also den letzten Indexwert der Tabelle zurück, an dem noch ein Element steht. Gibt es keine Elemente in der Tabelle, wird NULL zurückgeliefert. Die Syntax ist:
Die EXISTS FunktionDie wohl wichtigste Funktion im Umgang mit PL/SQL Tabellen, um den Zugriff auf uninitialisierte Zeilen und damit die NO_DATA_FOUND Ausnahme zu vermeiden: Die EXISTS Funktion liefert TRUE zurück, wenn am gegebenen Index ein Element (auch NULL) eingetragen ist, andernfalls FALSE. Sie kann beispielsweise so verwendet werden:
The PRIOR FunctionDie PRIOR Funktion ist das Gegenteil der NEXT Funktion. PRIOR liefert den nächstkleineren Indexwert, an dem ein Element steht, für einen gegebenen Indexwert zurück. Sie liefert NULL, wenn es kein Element mit einem kleineren Indexwert gibt. Beispiel:
Ein Beispiel für die Arbeit mit PL/SQL TabellenLassen Sie uns nun anschauen, wie PL/SQL Tabellen am einfachsten mit Daten gefüllt werden können. Es ist nicht ganz so einfach wie ein SELECT INTO, um einzelne Spaltenwerte in Variablen zu lesen. Wir müssen den Lesevorgang selbst programmieren. Wir müssen einen PL/SQL Block schreiben, der die Daten in eine PL/SQL Tabelle übernimmt. Die notwendigen Schritte sind folgende:
Schauen wir uns ein wenig Code an:
Nun, alternativ können wir eine PL/SQL Tabelle aber auch einfacher füllen:
In diesem Beispiel nutzen wir einen impliziten Cursor und übernehmen alle Datensätze in unsere PL/SQL Tabelle mit einem sogenannten BULK COLLECT, das mit der Version PL/SQL-Version 2.3 eingeführt wurde.
|
||||


Kommentare
"SELECT id, name, age, sex, comm_date, salary"
mit "SELECT *" gleichzusetzen ist.
Hatte in meinem Beispiel nicht alle Spalten der Tabelle selektiert, daher war employee_rec vom falschen Typ. Zitieren
nein, das ist kein Fehler. Die Eindimensionali tät, die Du anspricht, bleibt auch bei Bezug auf eine Tabelle erhalten. Schau nochmal im Artikel zu Records: Der Zusatz %ROWTYPE erzeugt einen Record, in obigem Beispiel sorgt der TYPE TABLE OF dafür, dass es sich um eine PL/SQL-Tabelle handelt. Aber: Es wäre wahrscheinlich bessere Programmierprax is, sich auf den Cursor zu beziehen, denn wenn sich das Select des Cursor ändern würde, wäre die zu füllende Tabelle nicht mehr vom korrekten Typ. Dein Vorschlag ist insofern gut, denn dann wäre die PL/SQL-Table immer vom gleichen Typ des Cursors, unabhängig davon, welche Spalten der Cursor nun konkret selekiert. Zitieren
"TYPE local_employees IS TABLE of employees%ROWTYPE"
müsste
"TYPE local_employees IS TABLE of c_employees%ROWTYPE"
also vom Cursor abgeleitet sein, sonst ist die Eindimensionali tät der PLSQL-table nicht gewährleistet. Zitieren
ich denke, wir haben einfach zwei unterschiedlich e Argumentationen :
Nehmen wir an, die Tabelle hat nur an Indexwert 1 und 20 eine Wertausprägung.
Dann löscht delete(20) nach meiner Argumentation die 20.Zeile (also die mit Indexwert 20). Die Zeilen 2 bis 19 sind ja auch potentielle Zeilen, die lediglich nicht initialisiert sind.
Ein delete(19) scheitert, weil Du sagst, die Zeile mit Indexwert 19 existiert nicht, ich sage: die 19. Zeile existiert nicht.
Ich glaube, es sind nur unterschiedlich e Formulierungen und hoffe, Deine Variante der Erklärung trägt zusätzlich zum Verständnis von PL/SQL-Tabellen bei.
Spätestens, wenn es nicht mehr BINARY_INTEGER sind, sondern ein INDEX BY VARCHAR2, ist Deine Formulierung wesentlich geschickter.
Liebe Grüße
Martin Zitieren
Die Beispiele für die DELETE Anweisung sind aber nicht alle korrekt:
table_name.delete(20) entfernt nicht die 20. Zeile sondern die Zeile mit Indexwert 20;
table_name.delete(20,50) entfernt nicht die 20. bis zur 50. Zeile sondern die Zeilen met Indexwerte 20 bis 50 Zitieren
BULK COLLECT funktioniert aber nur, wenn INDEX BY BINARY_INEGER ist. Zitieren
Alle Kommentare dieses Beitrages als RSS-Feed.