SQL

Oracle unterstützt die Speicherung und Bearbeitung von großen Binär- und Textdateien. Die Arbeit mit diesen Datentypen hat sich zwar der Verarbeitung ...
2MB Größe 458 Downloads 857 Ansichten
1452.book Seite 1 Donnerstag, 5. August 2010 3:55 15

Jürgen Sieben

Oracle PL/SQL Das umfassende Handbuch

1452.book Seite 3 Donnerstag, 5. August 2010 3:55 15

Auf einen Blick 1

Einführung ...........................................................................

17

2

Verwendete Werkzeuge und Ressourcen ..............................

29

TEIL I Grundlagen .........................................................................

53

3

Aufbau der Datenbank aus Sicht eines Programmierers ........

55

4

Datensicherheit, -konsistenz und Transaktion .......................

127

5

Die Datenbank in der Anwendungsarchitektur .....................

181

6

Programmierung der Datenbank ..........................................

223

TEIL II Die Sprache PL/SQL .......................................................... 247 7

Die Blockstruktur und Syntax von PL/SQL ............................

249

8

Events in der Datenbank: Programmierung von Triggern ......

345

9

Das Arbeiten mit Daten .......................................................

395

10

Packages ..............................................................................

441

11

Fehlerbehandlung ................................................................

483

TEIL III PL/SQL im Einsatz ........................................................... 511 12

Erweiterung von SQL ...........................................................

513

13

Arbeiten mit großen Datenstrukturen ...................................

559

14

Arbeiten mit XML ................................................................

603

15

Objektorientierung ...............................................................

681

16

Integration von Oracle in Applikationen ...............................

725

TEIL IV Workshops ...................................................................... 755 17 18

Workshop 1: Die Keimzelle sicherer Datenbankanwendungen .....................................................

757

Workshop 2: Ein Logging-Package ........................................

777

3

1452.book Seite 5 Donnerstag, 5. August 2010 3:55 15

Inhalt Die Oracle-Datenbank ist eines der mächtigsten und umfangreichsten relationalen Datenbanksysteme. Schon SQL ist ungeheuer vielseitig einsetzbar. Doch erst mit PL/SQL erschließt sich das gesamte Potenzial. Daher ist die Kenntnis von PL/SQL für jeden, der sich mit Oracle beschäftigt, essenziell. 17

1

Einführung .............................................................................. 17 1.1 1.2

1.3

Für wen ist dieses Buch geschrieben? ......................................... Der Aufbau des Buches .............................................................. 1.2.1 Teil 1: Grundlagen ........................................................ 1.2.2 Teil 2: Die Sprache PL/SQL ............................................ 1.2.3 Teil 3: PL/SQL im Einsatz .............................................. 1.2.4 Teil 4: Workshops ......................................................... Danksagung ...............................................................................

17 21 21 23 24 26 27

Damit wir uns im Folgenden auf die Themen konzentrieren können, erspare ich mir die dauernden Verweise auf die Online-Dokumentation oder die in diesem Buch verwendeten Werkzeuge. Stattdessen gebe ich Ihnen hier einen Überblick. 29

2

Verwendete Werkzeuge und Ressourcen .............................. 29 2.1

2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11

Oracles Online-Dokumentation ................................................. 2.1.1 Wo finde ich die benötigten Informationen? ................. 2.1.2 PL/SQL-Grundlagen ...................................................... 2.1.3 Oracle Packages ............................................................ 2.1.4 Weiterführende Literatur .............................................. Aufsetzen einer Beispieldatenbank ............................................. SQL*Plus ................................................................................... SQL-Developer .......................................................................... »explain plan« ............................................................................ Autotrace .................................................................................. RunStats .................................................................................... Trace und TKProf ....................................................................... DBMS_Profiler ........................................................................... Debugger .................................................................................. Die Beispielskripte .....................................................................

29 30 33 34 34 35 38 40 41 43 45 46 50 51 52

TEIL I Grundlagen In einem ersten Rundblick betrachten wir die Oracle-Datenbank aus Sicht eines Entwicklers. Hier lernen Sie die wichtigsten Strukturen und Arbeitsweisen für die Erstellung einer effizienten und skalierbaren Applikation kennen. 55

3

Aufbau der Datenbank aus Sicht eines Programmierers ....... 55 3.1

3.2

Instanz und Speicherstrukturen .................................................. 3.1.1 Die Speicherbereiche der SGA ....................................... 3.1.2 Shared Pool .................................................................. 3.1.3 Die Hintergrundprozesse ............................................... Die physikalische Datenbank ..................................................... 3.2.1 Datendateien ................................................................

56 57 59 60 65 65

5

1452.book Seite 6 Donnerstag, 5. August 2010 3:55 15

Inhalt

3.3

3.4 3.5

3.6

3.7

3.8

3.2.2 Redo-Log-Dateien ......................................................... 3.2.3 Kontrolldatei ................................................................. Parameter- und Passwortdatei ................................................... 3.3.1 Parameterdatei ............................................................. 3.3.2 Passwortdatei ............................................................... Start der Datenbank .................................................................. Verbindungsaufbau zur Datenbank ............................................ 3.5.1 Verbindungsarten und Treiber ....................................... 3.5.2 DEDICATED SERVER-Verbindung ................................. 3.5.3 Shared-Server-Verbindung ............................................ 3.5.4 Database Resident Connection Pool .............................. 3.5.5 Und nun? Entscheidungshilfen für den Verbindungsaufbau ....................................................... Logischer Aufbau: Schema, Tablespace & Co. ............................. 3.6.1 Schema ......................................................................... 3.6.2 Tablespace .................................................................... 3.6.3 Auswirkungen auf die Architektur einer Applikation....... Datenbankobjekte ..................................................................... 3.7.1 Tabellen ........................................................................ 3.7.2 Index ............................................................................ 3.7.3 Materialisierte Sichten .................................................. 3.7.4 PL/SQL-Konstrukte ....................................................... 3.7.5 Sonstige Datenbankobjekte ........................................... Exkurs: Zeichensatzkodierung .................................................... 3.8.1 Zeichensatzkodierung im Überblick ............................... 3.8.2 Zeichensatzkodierung bei Oracle ...................................

66 67 67 67 68 69 70 72 78 79 81 84 87 88 93 96 99 99 105 113 115 115 120 120 122

Jedes Datenbankmanagementsystem ist anders implementiert. Obwohl viele Anwender hoffen , alle Datenbanken seien gleich und können als homogene Datenpumpen betrachtet werden, unterscheiden sie sich grundlegend und fundamental. Kaum ein Bereich der Implementierungsunterschiede ist so ausgeprägt und gleichzeitig so wichtig wie der Bereich der Datensicherheit, der Datenkonsistenz und der Transaktion. Dieses Kapitel befasst sich mit der Implementierung dieser Strategien in Oracle. 127

4

Datensicherheit, -konsistenz und Transaktion ...................... 127 4.1

4.2

4.3

6

Lese- und Schreibkonsistenz ...................................................... 4.1.1 Lesekonsistenz .............................................................. 4.1.2 Schreibkonsistenz .......................................................... Transaktion ................................................................................ 4.2.1 Transaktion zum Schutz der Lesekonsistenz ................... 4.2.2 Transaktion zur Definition eines Geschäftsvorfalls........... 4.2.3 Zusammenfassung ......................................................... Datenkonsistenz und referenzielle Integrität .............................. 4.3.1 Datenintegrität ............................................................. 4.3.2 Performanzüberlegungen zu Datenbank-Constraints ...... 4.3.3 Datenkonsistenz ........................................................... 4.3.4 Zusammenfassung .........................................................

128 128 132 132 133 135 136 137 138 143 146 150

1452.book Seite 7 Donnerstag, 5. August 2010 3:55 15

Inhalt

4.4

4.5

4.6

4.7 4.8

Explizites Sperren von Daten durch die Anwendung .................. 4.4.1 Das Problem: Lost Updates ........................................... 4.4.2 Das optimistische Sperren ............................................. 4.4.3 Das pessimistische Sperren ............................................ 4.4.4 Do it the Oracle way: das vorsichtig optimistische Sperren ......................................................................... 4.4.5 Und nun? Wann sollte welche Sperrstrategie verwendet werden? ...................................................... Verarbeitung einer SQL-Anweisung ........................................... 4.5.1 Parsen und Optimierung ............................................... 4.5.2 Datenlieferung über Cursor ........................................... Die Sperrmechanismen von Oracle ............................................ 4.6.1 Locks ............................................................................ 4.6.2 Latches ......................................................................... Datensicherheit ......................................................................... Beispiel zum Einfluss der Programmierung ................................. 4.8.1 Das Ziel unserer Programmierung .................................. 4.8.2 Implementierung des Tests ...........................................

150 151 153 155 156 157 158 159 164 165 165 166 166 169 170 171

Ist die Datenbank eine Datenpumpe? Viele Anwendungen betrachten die Datenbank lediglich als Lieferant für Daten, die von der Anwendung konsumiert werden, und als Speicher für die Anwendungsdaten. Zentrale Konzepte wie die Datenkonsistenz oder die Datensicherheit gehen bei diesem Ansatz verloren, ebenso wie der Großteil der ansonsten möglichen Performanz. Sehen wir uns also die Datenbank im Kontext der Anwendung genauer an. 181

5

Die Datenbank in der Anwendungsarchitektur ..................... 181 5.1

5.2

5.3

5.4

Das Problem des Impedance Mismatch ..................................... 5.1.1 Das Problem der Identität ............................................. 5.1.2 Das Problem der Datensuche ........................................ 5.1.3 Das Problem der Lesestrategie ...................................... 5.1.4 Das Problem der Vererbung .......................................... 5.1.5 Das Problem der Kopplung von Logik und Daten ........... 5.1.6 Das Problem der referenziellen Integrität ...................... Lösungsansatz 1: Die Vision der generischen Datenbank ............ 5.2.1 Generisches SQL ........................................................... 5.2.2 Generisches Abfragewerkzeug ....................................... 5.2.3 Die Kosten generischer Datenbankprogrammierung ....... Lösungsansatz 2: Objektrelationale Mappingwerkzeuge ............. 5.3.1 Abbildung der Objekte auf Tabellen .............................. 5.3.2 Kapselung der SQL-Dialekte .......................................... 5.3.3 Caching-Mechanismen, Lazy Load ................................. 5.3.4 Transaktionsverwaltung ................................................. 5.3.5 Zusammenfassung ......................................................... Lösungsansatz 3: Die Datenbank als Datenframework ................ 5.4.1 Performanz der Datenbearbeitung ................................ 5.4.2 Sicherheitsdomäne ........................................................ 5.4.3 Integration von PL/SQL und SQL ...................................

183 183 184 186 188 191 192 193 193 197 198 200 200 201 201 201 202 203 204 205 208

7

1452.book Seite 8 Donnerstag, 5. August 2010 3:55 15

Inhalt

5.5

Mächtigkeit von SQL ................................................................. 5.5.1 Analytische Funktionen ................................................. 5.5.2 Hierarchische Abfragen ................................................. 5.5.3 Error Logging ................................................................ 5.5.4 Fazit ..............................................................................

209 210 212 216 221

Die Oracle-Datenbank kann von PL/SQL-Programmen in vielerlei Bereichen profitieren. Bevor wir uns der Sprache und ihrer Syntax zuwenden, sehen wir uns an, für welche Einsatzszenarien PL/SQL normalerweise verwendet wird. 223

6

Programmierung der Datenbank ........................................... 223 6.1 6.2

6.3 6.4

6.5

Erweiterung der Datenbankfunktionalität .................................. Programmierung der Datenkonsistenz ....................................... 6.2.1 Datenbanktrigger .......................................................... 6.2.2 Datenzugriff über PL/SQL .............................................. 6.2.3 Datenkonsistenz jenseits referenzieller Integrität ............ Programmierung der Datensicherheit ......................................... Anwendungsprogrammierung mit PL/SQL ................................. 6.4.1 PL/SQL auf der Clientseite ............................................. 6.4.2 Webanwendungen mit PL/SQL entwickeln .................... Unterstützung der Administration durch PL/SQL ........................ 6.5.1 Einsatz von PL/SQL in Skripten ...................................... 6.5.2 Verwaltung wiederkehrender Aufgaben mit Scheduler und Jobs ....................................................................... 6.5.3 Datenbanktrigger im Umfeld der Datensicherung und des Auditings .........................................................

223 225 225 229 232 233 236 237 238 242 243 244 245

TEIL II Die Sprache PL/SQL Genug der Vorbereitung: Nun geht es an die Definition der Sprache PL/SQL und an die Strukturen, die Sie kennen müssen, um eigene Programme entwerfen zu können. Dieses Kapitel führt zunächst in die grundlegenden Strukturen ein. Sie lernen die Blockstruktur sowie die wichtigsten Anweisungen von PL/SQL kennen. 249

7

Die Blockstruktur und Syntax von PL/SQL ............................ 249 7.1

7.2

8

Vom anonymen Block zum Package ........................................... 7.1.1 Das Grundgerüst: Der PL/SQL-Block ............................. 7.1.2 Prozeduren ................................................................... 7.1.3 Funktionen ................................................................... 7.1.4 Datenbanktrigger .......................................................... 7.1.5 Packages ....................................................................... 7.1.6 Ausführungsrechte von PL/SQL-Blöcken (AUTHID-Klausel) ......................................................... 7.1.7 Kompileranweisungen (PRAGMA-Klausel) .................... 7.1.8 Best Practices ............................................................... PL/SQL-Datentypen ................................................................... 7.2.1 SQL-Datentypen ........................................................... 7.2.2 Basistypen und Subtypen in PL/SQL ..............................

250 250 256 266 269 272 276 279 281 282 282 284

1452.book Seite 9 Donnerstag, 5. August 2010 3:55 15

Inhalt

7.2.3

7.3

7.4

7.5

7.6

SQL-Datentypen mit abweichender Definition in PL/SQL ...................................................................... 7.2.4 SQL-Datentypen, die in PL/SQL nicht existieren............. 7.2.5 PL/SQL-Datentypen, die in SQL nicht existieren............. 7.2.6 Benutzerdefinierte Datentypen ..................................... 7.2.7 Ableitung von Variablentypen aus dem Data Dictionary ..................................................................... Kontrollstrukturen ..................................................................... 7.3.1 Bedingte Anweisung 1 (IF-THEN-ELSE-Anweisung) ........ 7.3.2 Bedingte Anweisung 2 (CASE-Anweisung) ..................... 7.3.3 Konditionale Kompilierung ........................................... 7.3.4 Einfache Schleifen (LOOP-Anweisung) .......................... 7.3.5 Abweisende Schleife 1 (FOR-LOOP-Anweisung) ............ 7.3.6 Abweisende Schleife 2 (WHILE-LOOP-Anweisung) ....... 7.3.7 Best Practices ................................................................ 7.3.8 Aus der Mottenkiste: Konzepte, die Sie nicht verwenden sollten ......................................................... Kollektionen in PL/SQL .............................................................. 7.4.1 Record .......................................................................... 7.4.2 Assoziative Tabellen ...................................................... 7.4.3 Cursor ........................................................................... Dynamisches SQL ...................................................................... 7.5.1 Natives dynamisches SQL (Execute-Immediate-Anweisung) ................................... 7.5.2 Dynamisches SQL mit Cursorvariablen ........................... 7.5.3 DBMS_SQL-Package ..................................................... 7.5.4 Sicherheit bei dynamischem SQL ................................... Objektorientierte Datentypen .................................................... 7.6.1 VARRAY ....................................................................... 7.6.2 Geschachtelte Tabellen (nested tables) ..........................

286 287 287 288 288 291 291 292 295 300 301 303 304 307 310 310 314 316 324 325 328 330 333 337 337 341

Triggerprogrammierung ist ein komplexes, manchmal etwas hakeliges Thema. Neben den unbestreitbaren Vorteilen von Triggern lauern einige logische Stolperfallen sowie da und dort einige nicht ganz intuitive Einschränkungen. Grund genug, Trigger einmal etwas genauer anzusehen. 345

8

Events in der Datenbank: Programmierung von Triggern ..... 345 8.1

8.2

DML-Trigger .............................................................................. 8.1.1 Anweisungs- versus Zeilentrigger .................................. 8.1.2 Wann wird ein Trigger ausgelöst? .................................. 8.1.3 Das Mutating-Table-Problem ........................................ 8.1.4 Compound-Trigger ........................................................ 8.1.5 Instead-Of-Trigger ........................................................ Datenbank-Trigger ..................................................................... 8.2.1 Ereignisattribute ............................................................

345 347 351 353 355 357 359 360

9

1452.book Seite 10 Donnerstag, 5. August 2010 3:55 15

Inhalt

8.3

8.4

8.2.2 Datenbankereignisse ..................................................... 8.2.3 Benutzerbezogene Ereignisse ........................................ Einsatzbereiche von Triggern ..................................................... 8.3.1 Datenintegrität durchsetzen .......................................... 8.3.2 DML-Ereignisse, die von Triggern überwacht werden..... 8.3.3 Auditierung mithilfe von Triggern .................................. 8.3.4 Historisierung von Daten ............................................... 8.3.5 Trigger und Datensichten (INSTEAD-OF-Trigger)............ 8.3.6 DDL-Ereignisse ............................................................. 8.3.7 System-Ereignisse .......................................................... Zusammenfassung .....................................................................

362 364 367 367 369 375 377 381 389 391 391

Die zentrale Aufgabenstellung für die Programmierung von PL/SQL ist der Umgang mit den Daten der Datenbank. PL/SQL ist für diese Aufgabe besser gerüstet als jede andere Programmiersprache im Oracle-Umfeld, denn als Erweiterung zu SQL setzt sie direkt auf der Datenbanksprache auf. Grund genug, diese Vorteile zu nutzen! 395

9

Das Arbeiten mit Daten ......................................................... 395 9.1

9.2

9.3

Strukturierte Variablen: Records und Typen ............................... 9.1.1 Bindung an das Data Dictionary mit »%TYPE« und »%ROWTYPE« .............................................................. 9.1.2 Insert- und Update-Anweisungen mit Records ............... 9.1.3 Verwendung explizit deklarierter Records ..................... 9.1.4 Verwendung der Returning-Klausel mit Records ............ 9.1.5 Alternative zum Record: Objekt .................................... PL/SQL-Kollektionen ................................................................. 9.2.1 Verwendung von assoziativen Tabellen ......................... 9.2.2 Massenverarbeitung mit assoziativen Tabellen ............... 9.2.3 Tabellenfunktionen (PIPELINED-Functions) ................... Mengenverarbeitung mit Cursorn .............................................. 9.3.1 Implizite versus explizite Cursor .................................... 9.3.2 Top-N-Analyse .............................................................. 9.3.3 Cursorvariablen (REF-Cursor) ......................................... 9.3.4 Cursor-Ausdrücke .........................................................

395 395 398 401 404 406 407 407 409 415 423 423 429 432 435

PL/SQL-Code wird in Packages organisiert. Doch über das reine Organisieren von Code hinaus bieten Packages einen erheblichen Mehrwert, der die Programmierung in PL/SQL erst zu ihrer vollen Leistungsfähigkeit führt. Dieses Kapitel beleuchtet Strategien und Möglichkeiten des Einsatzes von Packages und wirft einen Blick auf die mitgelieferten Packages von Oracle. 441

10 Packages ................................................................................. 441 10.1

10.2

10

Warum sollten Packages genutzt werden? ................................. 10.1.1 Trennung von öffentlicher und privater Logik ................ 10.1.2 Überladung in Packages ................................................ 10.1.3 Packages und die Abhängigkeitskette ............................ 10.1.4 Verschlüsselung von Package-Code ............................... Oracle-Packages ........................................................................ 10.2.1 Das Package »standard« ................................................ 10.2.2 Wichtige Oracle-Packages .............................................

441 442 452 458 464 470 473 474

1452.book Seite 11 Donnerstag, 5. August 2010 3:55 15

Inhalt

Die Fehlerbehandlung ist ein zentraler, aber nicht eben beliebter Teil jeder Programmiersprache. Wir beschäftigen uns selbstverständlich dennoch mit der Fehlerbehandlung und zeigen die Möglichkeiten der Sprache PL/SQL auf. 483

11 Fehlerbehandlung ................................................................... 483 11.1

11.2

11.3 11.4

Oracle-Fehler ............................................................................. 11.1.1 Benannte Fehler ............................................................ 11.1.2 »SQLERRM« und »SQLCODE«-Funktionen und der Fehlerstack .................................................................... 11.1.3 Nicht benannte Fehler benennen .................................. Applikationsfehler erstellen und bearbeiten ............................... 11.2.1 Fehler direkt mit RAISE_APPLICATION_ERROR erzeugen ....................................................................... 11.2.2 Fehler aus einem Fehlerpackage erstellen lassen............. 11.2.3 Zentralisierung der Fehlermeldungen über »LMSGEN« ..... Zentralisierter Fehlerhandler mit einem Trigger .......................... Zusammenfassung .....................................................................

483 489 491 494 495 495 496 498 505 510

TEIL III PL/SQL im Einsatz Die Erweiterung von SQL ist das natürliche Anwendungsgebiet von PL/SQL. Wir überlegen, wann eine Erweiterung durch PL/SQL sinnvoll ist und welcher Preis dafür gezahlt werden muss, und wir schrecken auch vor fortgeschrittenen Themen nicht zurück. 513

12 Erweiterung von SQL ............................................................. 513 12.1

12.2

12.3 12.4

12.5

Wann SQL erweitert werden sollte ............................................ 12.1.1 Bleiben Sie auf dem aktuellen Wissensstand! ................ 12.1.2 Voraussetzungen für die Erweiterung von SQL ............... SQL mit eigenen Funktionen erweitern ...................................... 12.2.1 Anforderungen an den PL/SQL-Block ............................ 12.2.2 Nebenwirkungsfreiheit (Purity) ...................................... 12.2.3 Optimizer Hints ............................................................ 12.2.4 Das Pragma »restrict_references« .................................. 12.2.5 Beispielfunktion ............................................................ Code-Beispiel: Berechnung der Fakultät ..................................... Gruppenfunktionen selbst erstellen ........................................... 12.4.1 Arbeitsweise von Gruppenfunktionen ........................... 12.4.2 Beispiel ......................................................................... 12.4.3 Test der Gruppenfunktion ............................................. 12.4.4 Zusammenfassung ......................................................... Code-Beispiel: Codegenerator für Gruppenfunktionen ...............

513 514 517 519 519 520 520 521 522 528 538 539 542 547 548 549

Oracle unterstützt die Speicherung und Bearbeitung von großen Binär- und Textdateien. Die Arbeit mit diesen Datentypen hat sich zwar der Verarbeitung normaler Zeichenketten oder Raw-Daten angeglichen, doch gibt es immer noch Unterschiede, die beachtet werden müssen. Dieses Kapitel führt in die Bearbeitung dieser Datenstrukturen ein. 559

13 Arbeiten mit großen Datenstrukturen ................................... 559 13.1

Technische Struktur ................................................................... 560 13.1.1 Einsatz von LOB-Datentypen in der Datenbank.............. 560 13.1.2 LOBs als PL/SQL-Variablen ............................................ 565

11

1452.book Seite 12 Donnerstag, 5. August 2010 3:55 15

Inhalt

13.2

13.3

13.4

13.1.3 LOBs als Methodenparameter ....................................... 13.1.4 Secure Files ................................................................... Die Datentypen CLOB, NCLOB, BLOB und BFILE ....................... 13.2.1 CLOB und NCLOB ......................................................... 13.2.2 Der binäre Datentyp BLOB ............................................ 13.2.3 BFILE ............................................................................ Das Package DBMS_LOB ........................................................... 13.3.1 Schreibzugriff auf temporäre oder persistente LOBs ....... 13.3.2 Verwaltung temporärer und persistenter LOBs ............... 13.3.3 API für Bfile-LOBs ......................................................... Hilfsfunktionen zum Arbeiten mit LOBs ..................................... 13.4.1 Hilfsfunktion zum Laden von CLOBs und BLOBs aus dem Dateisystem in die Datenbank ............................... 13.4.2 Hilfsfunktion zum Lesen von CLOBs und BLOBs aus der Datenbank ..............................................................

571 572 575 575 576 576 578 579 581 583 584 584 592

XML ist eine Kerntechnologie zur Übermittlung von Daten zwischen Systemen, zur Speicherung umfangreicher Dokumente und als Bindeglied zwischen objektorientierter und relationaler Datenhaltung und -verarbeitung. Dieses Kapitel beleuchtet die umfangreiche Unterstützung des Standards durch die verschiedenen Oracle-Technologien. 603

14 Arbeiten mit XML ................................................................... 603 14.1

14.2 14.3

14.4 14.5

14.6

12

Der Datentyp »XMLType« .......................................................... 14.1.1 Verwendung von »XMLType« als Tabellen- oder Spaltentyp .................................................................... 14.1.2 »XMLType«-Methoden ................................................. Die Speicherung von XML-Daten in der Datenbank ................... XML aus relationalen Daten erzeugen ........................................ 14.3.1 Der SQL/XML-Standard ................................................ 14.3.2 Das Package »dbms_xmlgen« ........................................ Relationale Daten aus XML extrahieren ..................................... XML mit PL/SQL verarbeiten ..................................................... 14.5.1 Die Programmierung von XML ...................................... 14.5.2 Die XML-Packages ........................................................ Die XML-Datenbank .................................................................. 14.6.1 Einführung in die XML-Datenbank ................................ 14.6.2 Speicherung und Veröffentlichung binärer und XML-Dokumente .......................................................... 14.6.3 Dokumente über XDB verwalten ................................... 14.6.4 Zugriffsschutz und Sicherheit der XDB ........................... 14.6.5 Versionierung von Ressourcen ......................................

606 606 611 613 615 615 621 631 638 638 640 651 652 654 659 670 676

1452.book Seite 13 Donnerstag, 5. August 2010 3:55 15

Inhalt

Kaum eine Funktionalität der Oracle-Datenbank hat so kontroverse Diskussionen ausgelöst wie die Integration objektorientierter Techniken. In diesem Kapitel zeige ich die Vor- und Nachteile dieser Techniken auf und stelle Ihnen sinnvolle Einsatzgebiete vor. 681

15 Objektorientierung ................................................................ 681 15.1

15.2 15.3

15.4

Einführung in die Objektorientierung ......................................... 15.1.1 Alles ist ein Objekt ........................................................ 15.1.2 Das zweite Reizwort: Vererbung! .................................. 15.1.3 Abstrakte und finale Klassen ......................................... 15.1.4 Statische Methoden ...................................................... 15.1.5 Objektidentität versus »Statement of Truth« .................. 15.1.6 Klassen haben komplexe Strukturen .............................. 15.1.7 Auswirkungen auf die Datenbankprogrammierung ......... Typen ........................................................................................ Anwendungsbeispiel: Der Datentyp »MoneyType« .................... 15.3.1 Vorüberlegungen .......................................................... 15.3.2 Implementierung des »MoneyType« .............................. 15.3.3 Der Typkörper ............................................................... 15.3.4 Implementierung des Packages »coa_money« ................ 15.3.5 Der Package-Körper ...................................................... 15.3.6 Die Rechtesituation in Version 11g ............................... 15.3.7 Erweiterung durch Vererbung ....................................... Best Practices ............................................................................

683 684 686 687 688 689 691 693 695 697 697 699 701 705 707 718 721 723

Dieses Kapitel beschäftigt sich mit der Integration von Oracle-Datenbanken in Anwendungen. Es wird uns hauptsächlich um strategische Fragen gehen, wie etwa die, welche Aufgaben wo erledigt werden sollten. Aber auch Techniken zur Integration kommen nicht zu kurz. 725

16 Integration von Oracle in Applikationen ............................... 725 16.1

16.2

16.3

16.4

16.5

Sperrung von Daten bei der Datenänderung .............................. 16.1.1 Pessimistisches Locking ................................................. 16.1.2 Optimistisches Locking ................................................. 16.1.3 Database-Change-Notification-basiertes Locking............ Zugriff auf Daten über PL/SQL-Packages .................................... 16.2.1 Kapselung von DML-Operationen in Packages ............... 16.2.2 Vermeidung von Triggern durch Packages ..................... 16.2.3 Integration datenbezogener Geschäftsregeln ................. Zugriff auf Daten über das Web ................................................. 16.3.1 Veröffentlichung von Packages über HTTP .................... 16.3.2 Schreiben von Daten in einen HTTP-Stream .................. 16.3.3 Webservices aus PL/SQL ............................................... Gemeinsamer Zugriff auf Daten über verteilte Cursor ................. 16.4.1 Prozeduren mit »REF_CURSOR«-Parametern ................. 16.4.2 Arbeit mit LOBs ............................................................ Zusammenfassung und Bewertung .............................................

726 727 733 741 743 744 745 746 748 749 749 750 751 751 752 753

13

1452.book Seite 14 Donnerstag, 5. August 2010 3:55 15

Inhalt

TEIL IV Workshops In diesem Workshop stelle ich Ihnen eine praktische Umsetzung der Empfehlungen vor, die ich Ihnen bezüglich der Nutzung der Datenbank als Datenframework gegeben habe. Wir werden eine Grundlage erarbeiten, die Sie als Keimzelle eigener Datenbankanwendungen verwenden können. 757

17 Workshop 1: Die Keimzelle sicherer Datenbankanwendungen ....................................................... 757 17.1

17.2 17.3 17.4 17.5

Das Projekt ................................................................................ 17.1.1 Übersicht über die Architektur ...................................... 17.1.2 Die Logon-Prozedur ...................................................... Aufsetzen der Schemata ............................................................ Die Packages ............................................................................. Test der Architektur ................................................................... Zusammenfassung und Ausblick .................................................

757 758 761 762 766 772 774

Zum Abschluss des Buches möchte ich mit Ihnen nun ein größeres Projekt besprechen, das für Ihre Projekte vielleicht wiederverwendbar ist. Es handelt sich um ein Package zum Logging und zur Fehlerbehandlung. 777

18 Workshop 2: Ein Logging-Package ........................................ 777 18.1

18.2

18.3

18.4

18.5

14

Überblick: Die Idee und die Architektur ..................................... 18.1.1 Meldung ....................................................................... 18.1.2 Kontext ......................................................................... 18.1.3 Ausgabemodule ............................................................ 18.1.4 Parameter- und Meldungstabelle .................................. 18.1.5 Meldungspackage ......................................................... Umsetzung des Logging-Packages .............................................. 18.2.1 Die Parametertabelle .................................................... 18.2.2 Die Meldungstabelle ..................................................... 18.2.3 Das Meldungsobjekt ..................................................... 18.2.4 Das Grundmodul ........................................................... 18.2.5 Kontext ......................................................................... 18.2.6 Parameterliste ............................................................... Implementierung des Logging-Packages .................................... 18.3.1 Die Package-Spezifikation des Logging-Packages............ 18.3.2 Der Package-Körper des Logging-Packages ................... 18.3.3 Test des Logging-Packages ............................................ Implementierung des Log-Administrations-Packages ................. 18.4.1 Funktionsüberblick und Implementierungsstrategie........ 18.4.2 Implementierung der Log-Administration-PackageSpezifikation ................................................................. 18.4.3 Implementierung des Log-AdministrationPackage-Körpers ........................................................... Weitere Ausgabemodule ........................................................... 18.5.1 Ausgabe in eigene Fehlerdateien ................................... 18.5.2 Ausgabe in Alert-Log- oder Trace-Dateien ....................

778 780 781 782 784 789 790 790 791 794 800 808 809 811 811 814 827 828 828 830 832 846 847 855

1452.book Seite 15 Donnerstag, 5. August 2010 3:55 15

Inhalt

18.5.3 Ausgabe in Logging-Tabellen ........................................ 856 18.5.4 Meldung als E-Mail versenden ...................................... 857 18.5.5 Meldungen in JMS integrieren ...................................... 859

Index .......................................................................................................... 865

15

1452.book Seite 17 Donnerstag, 5. August 2010 3:55 15

Die Oracle-Datenbank ist eines der mächtigsten und umfangreichsten relationalen Datenbanksysteme. Schon SQL ist ungeheuer vielseitig einsetzbar. Doch erst mit PL/SQL erschließt sich das gesamte Potenzial. Daher ist die Kenntnis von PL/SQL für jeden, der sich mit Oracle beschäftigt, essenziell.

1

Einführung

PL/SQL ist keine Programmiersprache. Das mag zunächst verwunderlich klingen, schließlich bedeutet PL/SQL Procedural Language for SQL, also eben das Gegenteil des Einleitungssatzes. Doch schon im ersten Satz von Oracle zur Einführung in PL/SQL heißt es: PL/SQL ist eine prozedurale Erweiterung von SQL. Dieser feine Unterschied ist sehr wichtig, auch für dieses Buch: Ein Buch über PL/SQL ist nicht komplett ohne ein Buch über SQL. Sollten Sie also ein Neueinsteiger in die Welt der Oracle-Datenbanken sein, sollte Ihr erstes Augenmerk auf der Abfragesprache SQL liegen, nicht auf PL/SQL. Die syntaktischen Grundlagen von PL/SQL, die Namenskonventionen, aber auch die überwältigende Mehrheit der Funktionen in PL/SQL kommen aus SQL. Das vorweggenommen, ist PL/SQL aber auch eine faszinierende Technologie, mit deren Hilfe Sie der Datenbank die mächtige Funktionalität abgewinnen können, die Sie sonst nur in sehr wenigen, anderen Datenbanken finden. Mit diesem Buch möchte ich Sie in die Sprache PL/SQL einführen und Ihnen erläutern, wie Sie aus der Datenbank maximalen Nutzen für Ihre Anwendung ziehen können.

1.1

Für wen ist dieses Buch geschrieben?

Nun, ganz eindeutig für Sie. Damit meine ich, dass die Konzeption dieses Buches natürlich kein Selbstzweck, sondern dem Ziel unterworfen ist, Ihnen zu erklären, wie und wofür PL/SQL einzusetzen ist, und eben nicht dem Ziel, einfach nur ein Buch über PL/SQL zu schreiben, das lediglich alle wichtigen Merkmale der Sprache auflistet. Daher habe ich mir zu Beginn Gedanken darüber gemacht, wer Sie eigentlich sind. Wer liest ein solches Buch? Ich stelle mir vor, dass Sie beruflich bereits mit Datenbanken zu tun hatten, auch schon programmiert haben und nun Ihre Kenntnisse und Fähigkeiten um PL/SQL erweitern möchten oder müssen.

17

1452.book Seite 18 Donnerstag, 5. August 2010 3:55 15

1

Einführung

Vielleicht sind Sie ein Administrator, der sich in die Programmierung von Triggern einarbeiten oder PL/SQL-Programme zur Erleichterung seiner Arbeit verfassen muss? Vielleicht sind Sie aber auch ein Anwendungsentwickler, der bislang in einer der Programmiersprachen für Anwendungsentwicklung programmiert hat und nun, freiwillig oder aufgrund von Performanzproblemen gezwungen, einen näheren Blick in die Datenbankinterna werfen will? Vielleicht sind Sie der Betreuer einer Software, die von anderen geschrieben wurde (vielleicht von Vorgängern im Amt) und Ihnen nun zur weiteren Betreuung überlassen wurde. Sind Sie ein absoluter Neuling in Datenbanken und wollen den Einstieg über PL/SQL erreichen? Nein, das glaube ich eigentlich nicht. Daher richte ich mein Buch an meiner Erwartung an Sie aus. Dieses Buch richtet sich einerseits an Leser, die SQL-Kenntnisse haben. PL/SQLBücher sind keine Einstiegsliteratur in Datenbanken, sondern setzen den Weg fort, den Sie durch die Auseinandersetzung mit relationalen Datenmodellen und SQL bereits begonnen haben. Ich setze nicht voraus, dass Ihre SQL-Kenntnisse sehr tiefgehend sind, doch ein Grundverständnis dieser Abfragesprache sollte in jedem Fall vorhanden sein. Dann gehe ich davon aus, dass Sie bereits in irgendeiner Programmiersprache programmiert haben. Ich kann mir einfach nicht recht vorstellen, dass Sie das Programmieren gerade innerhalb einer Datenbank lernen möchten (oder müssen). Normalerweise, das lehrt mich auch die Erfahrung aus den vielen Kursen, die ich zum Thema PL/SQL-Einführung gegeben habe, ist die Programmierung der Datenbank ein Thema für Menschen, die bereits Programmiererfahrung in anderen Sprachen, sei es Cobol, C, C++, Java oder VisualBasic, haben. Daher möchte ich Sie nicht langweilen und erläutere die Grundlagen einer If-Anweisung nur sehr kurz. Sollten Sie eine der beiden Voraussetzungen, die ich hier genannt habe, nicht mitbringen, empfehle ich Ihnen, sich zunächst mit diesen Themen zu beschäftigen. Insbesondere gilt diese Empfehlung für die Beschäftigung mit der Abfragesprache SQL. Je besser Sie diese Sprache beherrschen, umso leichter fällt es Ihnen, Aufgabenstellungen in Bezug auf Daten einer Datenbank zu lösen. Und auch das gilt: Je besser Sie SQL beherrschen, umso seltener müssen Sie zu einer Programmiersprache greifen, um ein Problem zu lösen. Das ist leider auch auf der Zeitachse wahr: Sollten Sie sich sehr gut mit dem SQL der Oracle-Datenbankversion 7.3.4 auskennen, werden Sie staunen, was seit dieser Zeit in SQL an Fähigkeiten hinzugekommen ist. Die Beschäftigung mit SQL ist immer die Beschäftigung mit SQL in der Datenbankversion Ihrer Datenbank. Für diejenigen unter Ihnen, die noch nicht programmiert haben, glaube ich, wird der Stoff relativ schnell und wenig didaktisch vorangehen. Vielleicht sollten Sie ins Auge fassen, die Programmierung vorab zu erlernen. Auch hier geht es weniger darum,

18

1452.book Seite 19 Donnerstag, 5. August 2010 3:55 15

Für wen ist dieses Buch geschrieben?

Experte in einer Programmiersprache zu sein, sondern um ein generelles Verständnis der Vorgehensweise beim Programmieren. Diese Einführung kann dieses Buch nicht leisten. Darüber hinaus muss ich eine – für mich sehr schwierige – Entscheidung treffen: Werden Sie als meine Leser eher Entwickler sein, Endanwender oder Administratoren? Welcher konkrete Einsatzzweck liegt Ihrem Interesse an PL/SQL zugrunde? Diese Entscheidung ist nicht leicht. Ich habe mich dafür entschieden, aus dem Blickwinkel des Entwicklers und des Administrators zu schauen; der Schwerpunkt liegt allerdings auf dem Blickwinkel des Entwicklers von Anwendungssoftware. Aus dieser Entscheidung resultieren mehrere Konsequenzen: 왘 Ich gehe davon aus, dass die meisten Anwendungsentwicklungen (insbesondere neu aufgesetzte Projekte) nicht mehr nur in einer Technologie allein entwickelt werden. Die aktuellen Architekturentscheidungen mit Webanwendungen, Applikationsservern und Datenbankservern lassen eine Entwicklung in einer Programmiersprache eigentlich auch nicht zu. Daher widme ich einigen Raum dieses Buches auch den Problemen der Integration von OracleDatenbanken in Anwendungen, die in anderen Programmiersprachen entwickelt werden. 왘 Ich gehe weiterhin davon aus, dass Datenbanken (nicht nur Oracle, sondern Datenbanken generell) vielen Anwendungsentwicklern nur als Datenspeicher geläufig sind und die Interna der Arbeitsweise ihnen nicht immer komplett bekannt sind. Daher gebe ich eine ausführliche Einführung in die Arbeitsweise von Oracle-Datenbanken. Diese Einführung wird für Administratoren bekannt und eventuell etwas oberflächlich sein, ist aus meiner Sicht für Entwickler aber unbedingt von Interesse, um zu verstehen, warum die Datenbank auf eine gewisse Weise programmiert werden will. Für Administratoren schließlich sind Kenntnisse einiger Aspekte der Anwendungsprogrammierung von unschätzbarem Wert, einfach, um zu verstehen, welche Problemstellungen durch Anwendungsentwickler in der Datenbank gelöst werden müssen. Daher empfehle ich die Abschnitte, die sich mit der Entwicklung von Anwendungen und der Integration von Oracle-Datenbanken in solche Anwendungen befassen, auch den Administratoren. 왘 Ich gehe schließlich davon aus, dass es wichtiger ist, zu erklären, warum etwas getan werden muss, als wie etwas getan werden muss. Anders gesagt: Dieses Buch ist keine Referenz zu PL/SQL, in der Sie im Index einen Befehl nachschlagen können und auf Seite 371 alle Parameter der Prozedur aufgelistet bekommen. Diese Funktion übernehmen die Online-Ressourcen, die bei Oracle auf einem sehr hohen Niveau sind, wesentlich besser. Allein die Dokumentation

19

1.1

1452.book Seite 20 Donnerstag, 5. August 2010 3:55 15

1

Einführung

der mitgelieferten Packages umfasst bei der Datenbankversion 11gR2 stolze 5.744 Seiten … Nebenbei sind das über 600 Seiten mehr als zu Datenbankversion 11gR1, und das bringt mich zum ersten Grund für meine Entscheidung, keine Referenz zu PL/SQL zu schreiben: Diese ist naturgemäß von der Version der Datenbank abhängig und daher schon veraltet, bevor sie ausgeliefert wird. Der zweite Grund ist, dass es mir ein besonderes Anliegen ist, Ihnen zu erklären, wie die Datenbank gut programmiert wird. Die Kunst besteht darin, der Datenbank bei der Erfüllung ihrer Aufgaben möglichst nicht im Wege zu stehen. Das ist gar nicht so leicht und gelingt nur, wenn Sie wissen, was Sie tun. Und genau dafür benötige ich Platz, den ich nicht durch Auflistungen von Prozedurparametern verschwenden wollte. Ich trete mit dem Ziel an, Ihnen zu erklären, was Sie tun müssen und warum, um eine gute Anwendung oder Anwendungsunterstützung zu erhalten. Messen Sie mich daran. Außerdem ist dies ein Buch, in dem ich meine Meinung kund tue. Vielleicht sollte ich so etwas nicht tun, und vielleicht reizt dies zum Widerspruch. Ich habe mich dennoch entschieden, meine persönliche Meinung darüber mitzuteilen, wie eine Datenbank, speziell eine Oracle-Datenbank, programmiert werden sollte. Die Meinung basiert auf meiner Berufserfahrung, in der ich viel Code gesehen habe. Aufgrund meines Berufes komme ich vor allem zu Kunden, deren Code nicht oder nicht gut genug läuft. Daher sehe ich viel Code so, wie er nicht geschrieben werden sollte. Meine Meinung reflektiert dabei die Erfahrungen, die ich in diesen Projekten gesammelt habe, aber natürlich auch den Input, den ich von vielen sehr guten Kollegen und Autoren eingesogen habe. Trotzdem mögen Sie über die Ausrichtung von Software anderer Meinung sein als ich. Vielleicht arbeiten Sie in einem Team aus erfahrenen PL/SQL-Entwicklern, die Ihnen sagen, dass das, was ich hier schreibe, gut und schön, im konkreten Unternehmensumfeld aber nicht umsetzbar sei. Ich bin weit davon entfernt, hier Einspruch anzumelden. Natürlich gibt es viele, gute Gründe für eine Position. Es gibt auch viele richtige Positionen. Allerdings gibt es noch mehr falsche Positionen. Gerade am Anfang ist es aber schwer, falsche von richtigen Positionen zu unterscheiden. Da jedoch gerade am Anfang eines Projekts Entscheidungen zugunsten oder zuungunsten einer Strategie fallen, die später nur schwer korrigierbar sind, empfinde ich es als richtig, auch in einem Einführungsbuch bereits eine richtige Position zu beziehen und Sie nicht mit dieser Einschätzung allein zu lassen. Sind Sie anderer Meinung, ist das natürlich kein Problem. Sie sollten lediglich eine begründete Meinung vertreten (können). Und schließlich: Ist es gerade eine Position, die ich vertrete, die Sie zum Widerspruch reizt und dazu anregt, eine eigene Position zu entwickeln, umso besser!

20

1452.book Seite 21 Donnerstag, 5. August 2010 3:55 15

Der Aufbau des Buches

1.2

Der Aufbau des Buches

Das folgende Kapitel 2 liefert zunächst Grundinformationen zu den verwendeten Werkzeugen und Ressourcen; dann beginnen die vier großen Teile, in die dieses Buch gegliedert ist. Diese Teile folgen dem Gedanken, dass ich zunächst die Grundlagen, sowohl der Datenbank als auch der Programmiersprache PL/SQL, besprechen möchte. Danach folgt ein Teil, der sich mit der Anwendung von PL/ SQL in konkreten Einsatzszenarien auseinandersetzt und weitergehende, technologische Konzepte erläutert. Den Abschluss bildet schließlich ein Teil mit konkreten Anwendungen in einer Form, die als Keimzelle für Ihre eigenen Projekte dienlich sein könnte.

1.2.1

Teil 1: Grundlagen

Dieser Teil hat auf den ersten Blick eigentlich wenig mit PL/SQL zu tun. Erläutert werden der Aufbau und die grundsätzliche Arbeitsweise der Oracle-Datenbank. Aus meiner Erfahrung aus unzähligen Oracle-Schulungen weiß ich allerdings, dass das Wissen um diese Strukturen nicht vorausgesetzt werden kann. Andererseits ist es genau dieses Wissen, dass die meisten Empfehlungen der weiteren Abschnitte begründet und Sie in die Lage versetzt, die Folgen Ihrer Programmierung besser abschätzen zu lernen. Woraus besteht eine Datenbank? Wie wird ein Fremdschlüssel eigentlich durchgesetzt? Ist dieser Fremdschlüssel teuer? Solche Fragen werden gestellt und beantwortet. Allerdings führt dieser Teil Sie noch erheblich weiter, denn wir werden uns auch um Fragen der Konsistenz von Leseabfragen, um Transaktionsschutz und ähnliche Probleme kümmern. Die Kenntnis dieser Dinge ist deshalb von fundamentaler Bedeutung für Sie als Entwickler, weil diese Dinge in jeder Datenbank anders gehandhabt werden und massive Auswirkungen auf die Fehlerfreiheit und die Skalierbarkeit Ihrer Anwendungen haben. Kapitel 3: Aufbau der Datenbank aus Sicht eines Programmierers Dieses Kapitel beginnt den Rundblick mit einem Blick auf die Speicherstrukturen der Datenbank, die Datenbankdateien und die zugeordneten Dateien wie etwa die Parameter- und Passwortdateien. Die Strukturen werden so erläutert, dass Sie eine Vorstellung von der Arbeitsweise bekommen und die Auswirkungen auf die Programmierung abschätzen können, nicht aber so, dass Sie anschließend als hauptamtlicher Administrator tätig werden können. Wir werden uns in diesem Kapitel aber auch um die grundlegende Arbeit mit der Datenbank kümmern: um das Anmelden und das Hoch- und Herunterfahren der Datenbank. Danach sehen wir uns die Datenstrukturen an, mit denen Sie auf logischer Ebene zu tun haben: Schema, Tablespace, die verschiedenen Datenbankobjekte. Den Abschluss macht

21

1.2

1452.book Seite 22 Donnerstag, 5. August 2010 3:55 15

1

Einführung

ein Exkurs in die Zeichensatzkodierung, die gerade im Zusammenhang mit Datenbanken von großer Bedeutung ist und oft Probleme nach sich zieht. Kapitel 4: Datensicherheit, -konsistenz und Transaktion Dieses Kapitel ist ein absoluter Schwerpunkt bezogen auf das Wissen, das Sie über Oracle haben müssen, wenn Sie Anwendungen gegen eine Oracle-Datenbank programmieren. Nirgendwo sonst sind die Implementierungsunterschiede zwischen Datenbankmanagementsystemen so groß und die Auswirkungen auf die Programmierung so weitgehend. Wir werden in diesem Kapitel die Themen Schreib- und Lesekonsistenz erläutern und uns um den Begriff der Transaktion kümmern. Schließlich werfen wir einen genaueren Blick auf das Themenfeld Datenkonsistenz und referenzielle Integrität, denn diese Punkte sind das zentrale Gut, das es in Ihrem Code zu verteidigen gilt. Anschließend betrachten wir das Sperrverfahren, das Oracle implementiert, um die Datenkonsistenz zu schützen, und sehen uns an, auf welche Weise Ihre Anwendung aufgebaut sein muss, um diese zu erhalten. Zum Abschluss des Kapitels fragen wir uns, wie Oracle eine SQL-Anweisung verarbeitet und diese Verarbeitung intern optimiert, und wir fragen uns, welche Auswirkungen diese Betrachtungen auf Ihre Programmierstrategie haben. Kapitel 5: Die Datenbank in der Anwendungsarchitektur Dieses Kapitel nimmt insofern eine Sonderstellung ein, als es eine spezielle Zielgruppe hat: den Anwendungsentwickler mit Erfahrung in objektorientierten Programmiersprachen. Gerade aus der Kombination objektorientierter Programmiersprachen und relationaler Datenbanken ergibt sich eine Reihe schwer zu lösender Probleme. Diese Probleme werden als Impedance Mismatch zusammengefasst und müssen gelöst werden, damit Ihre Anwendung stabil und sicher arbeiten kann. In diesem Kapitel beleuchte ich das Problem und zeige die verschiedenen Lösungswege auf, die in der Industrie normalerweise für dieses Problem verwendet werden. Kapitel 6: Programmierung der Datenbank Dieses Kapitel fasst die verschiedenen Einsatzbereiche zusammen, in denen PL/ SQL innerhalb der Datenbank eingesetzt werden kann. Die Idee ist, Ihnen eine Vorstellung von der Vielseitigkeit der Sprache zu geben. Oft ist man gefangen in den Problemlösungen, die man kennt, obwohl es bessere Wege zur Lösung eines Problems gibt. Ich werde Ihnen einige dieser Alternativen aufzeigen. Wir beschäftigen uns in diesem Kapitel mit PL/SQL zur Erweiterung der Datenbankfunktionalität, zur Programmierung der Datenkonsistenz und -sicherheit, sehen uns die Anwendungsprogrammierung mit PL/SQL an und fragen uns, auf welche Weise PL/SQL den Datenbankadministrator unterstützt.

22

1452.book Seite 23 Donnerstag, 5. August 2010 3:55 15

Der Aufbau des Buches

1.2.2

Teil 2: Die Sprache PL/SQL

In diesem Teil beschäftigen wir uns mit der Sprache PL/SQL auf grundlegendem Niveau. Es geht in diesem Teil darum, die Sprache syntaktisch vorzustellen und zu zeigen, welches Instrumentarium PL/SQL zur Lösung von Problemen bietet. Was ist das Besondere an PL/SQL? Welche Gemeinsamkeiten, aber auch Unterschiede gibt es zwischen PL/SQL und anderen Programmiersprachen? Kapitel 7: Blockstruktur und Syntax von PL/SQL In diesem Kapitel beginnen wir mit dem syntaktischen Aufbau von PL/SQL, seiner Blockstruktur, den Datentypen und Kontrollstrukturen. Dann sehen wir uns die – naturgemäß sehr ausgebauten – Fähigkeiten der Datenbank in der Verwaltung von Datenmengen an. Es schließt sich eine Einführung in dynamisches SQL und die objektorientierten Datentypen an. Mit diesem Instrumentarium haben Sie die Einzelbausteine kennengelernt, aus denen PL/SQL-Programme bestehen. Das Kapitel schließt mit einem Rundblick über die online verfügbare Dokumentation der Sprache, die Sie für die tägliche Arbeit benötigen, um sich über konkrete Funktionalitäten zu informieren. Kapitel 8: Events in der Datenbank: Programmierung von Triggern Trigger sind für viele Entwickler der Einstieg in die Programmierung von Datenbanken. Aber auch Administratoren haben oft mit dieser Art der Programmierung zu tun, um Geschäftsregeln durchzusetzen, Stammdatenänderungen zu protokollieren oder Datensicherheitsbestimmungen durchzusetzen. Dieses Kapitel gibt einen Überblick über das – alles andere als triviale – Thema der Programmierung von Triggern. Wir beschäftigen uns mit »normalen« DML-Triggern, aber auch mit DDL-Triggern und sehen uns mögliche Einsatzbereiche an. Kapitel 9: Das Arbeiten mit Daten Die Kernaufgabe von PL/SQL-Programmen ist die Verarbeitung von Daten der Datenbank. Daher kommt den Mechanismen der Datenbearbeitung innerhalb von PL/SQL eine besondere Bedeutung zu. Dieses Kapitel widmet sich ganz dieser Aufgabe und zeigt zunächst die strukturierten Datentypen, die PL/SQL anbietet, im Kontext dieser Aufgaben. Anschließend sehen wir uns spezialisierte Konstrukte von PL/SQL für diesen Einsatzzweck an, und Sie erlernen den korrekten Umgang mit Cursorn in der Datenbank. Kapitel 10: Packages PL/SQL-Code wird in Packages organisiert. Neben der Organisation von Codeblöcken haben Packages aber noch weitergehende Funktionen, die in diesem Kapitel

23

1.2

1452.book Seite 24 Donnerstag, 5. August 2010 3:55 15

1

Einführung

beleuchtet werden. Wir sehen uns die Konzepte der Packages an und diskutieren deren Auswirkungen auf die Praxis der Programmierung. Außerdem sehen wir uns wichtige, mitgelieferte Oracle-Packages an, und ich gebe Ihnen Tipps, wie und wo Sie sich über weitere Packages informieren können. Kapitel 11: Fehlerbehandlung Die Fehlerbehandlung in PL/SQL-Programmen wird in diesem Kapitel untersucht. Wir beginnen mit einer Betrachtung der grundsätzlichen Arbeitsweise der Fehlerbehandlung und überlegen, welche Alternativen für die Definition und Behandlung von Fehlern zur Verfügung stehen. Abschließend gebe ich Ihnen einige Empfehlungen zum sinnvollen Umgang mit Fehlern.

1.2.3

Teil 3: PL/SQL im Einsatz

Der dritte Teil des Buches beschäftigt sich mit dem Einsatz von PL/SQL. War Teil 2 eher technisch orientiert, so gehen wir in diesem Teil die Probleme eher aufgabenorientiert an. Wir überlegen, mit welchen Mitteln und wofür PL/SQL genutzt werden kann, und betrachten die verschiedenen Möglichkeiten an kurzen Beispielen. Das Ziel dieses Teils ist einerseits, Ihnen Anregungen zum Einsatz von PL/SQL zu geben und dies anhand von konkretem Code zu verdeutlichen. Andererseits zeige ich Ihnen an dem erstellten Code PL/SQL in etwas größeren Zusammenhängen und begründe Ihnen meine Entscheidung für die eine oder andere Implementierung. Kapitel 12: Erweiterung von SQL Dieses Kapitel betrachtet einige Beispiele für die Erweiterung des Befehlsumfangs von SQL durch eigene PL/SQL-Funktionen. Wir starten damit, dass wir uns fragen, wann SQL überhaupt durch eigene Funktionen erweitert werden sollte und sehen uns dann an, wie diese Erweiterung durchgeführt werden kann. Als Krönung werden wir eigene Gruppenfunktionen erstellen und einen Code-Generator entwickeln, der Sie bei der Erstellung von Gruppenfunktionen unterstützt. Kapitel 13: Arbeiten mit großen Datenstrukturen Eine häufige (und häufig nicht vollständig verstandene) Anforderung an Datenbankentwickler ist die Arbeit mit großen Datenstrukturen. Damit sind hier nicht große Ergebnismengen durch SQL-Abfragen gemeint, sondern große Datenstrukturen wie Videos, Audiodateien oder große Textdateien. Bei Oracle können diese Strukturen mühelos jeden Arbeitsspeicher sprengen und bedürfen daher einer besonderen Behandlung. Diese Behandlung erläutere ich in diesem Kapitel. Wir sehen uns zunächst die technische Struktur dieser großen Datenstrukturen an

24

1452.book Seite 25 Donnerstag, 5. August 2010 3:55 15

Der Aufbau des Buches

und analysieren anschließend die von Oracle zur Verfügung gestellten Packages, mit denen diese Strukturen verwaltet werden. Das Kapitel schließt mit einigen Hilfspackages zum Schreiben und Lesen dieser Datenstrukturen vom und ins Dateisystem ab. Kapitel 14: Arbeiten mit XML Schon seit vielen Jahren unterstützt Oracle den Datentyp XML nativ. Dieses Kapitel beschäftigt sich mit diesem enorm umfangreichen Thema und gibt eine Einführung in die verschiedenen Strategien, mit denen XML innerhalb der Datenbank erzeugt, gelesen und auf relationale Tabellen abgebildet werden kann. Allerdings liefert dieses Kapitel keine Einführung in XML oder die in diesem Kapitel verwendeten Technologien wie XSLT oder XSD. Einiges wird nur erwähnt, anderes am Beispiel gezeigt. Gerade dieses Thema wäre ausreichend für ein eigenes Fachbuch (und solche Bücher gibt es natürlich zu diesem Thema). Doch für das grundlegende Verständnis dieser Technologie sollte das hier Dargestellte durchaus reichen. Wir sehen uns zunächst den Datentyp XMLType an, mit dessen Hilfe XML in der Datenbank hauptsächlich gespeichert und bearbeitet wird. Dann sehen wir uns Strategien an, wie XML aus relationalen Daten erzeugt werden und mit PL/SQL verarbeitet werden kann. Ein weiterer Teil beschäftigt sich mit dem Einlesen und Verteilen von XML in die Datenbank. Zum Teil liefert dieses Kapitel auch spezielle Funktionen von SQL, die ich hier aufgenommen habe, weil sie nicht zum Standardwissen eines SQL-Entwicklers gehören, allerdings in Kombination mit PL/SQL erforderlich sind, um XML zu verarbeiten. Das Kapitel schließt mit einer Einführung in die XML-Datenbank, einer Anwendung der eingangs geschilderten XML-Datentypen zur Speicherung von XML und binären Daten in der Datenbank über das Dateisystem. Kapitel 15: Objektorientierung Die Objektorientierung ist für Anwendungsentwickler mit entsprechendem Hintergrund oftmals der Heilsbringer, für Administratoren und Anwendungsentwickler ohne diesen Hintergrund oftmals das Schimpfwort schlechthin. Dieses Kapitel versucht zu schlichten: Einerseits bietet es eine Einführung in die Objektorientierung für diejenigen, die sich noch nicht entschließen konnten, diese Weltsicht für sich zu entdecken, andererseits erläutert es für die anderen, warum die Objektorientierung, gerade im Zusammenhang mit der strukturierten Speicherung großer Datenmengen, nicht die allein selig machende Technologie sein kann. Wahrscheinlich, das sehe ich schon kommen, werden beide Seiten nach der Lektüre nicht vollends zufrieden sein: Meine Einführung in die Objektorientierung dürfte denen, die die Technologie bereits mit Begeisterung einsetzen, zu oberflächlich, die Argumente gegen den hemmungslosen Einsatz von Objektori-

25

1.2

1452.book Seite 26 Donnerstag, 5. August 2010 3:55 15

1

Einführung

entierung innerhalb der Datenbank zu kleinlich sein, und die Gegner der Objektorientierung werden mir möglicherweise ein unvorteilhaft positives Bild der objektorientierten Programmierung vorwerfen und den Aufwand, diese Technologie innerhalb der Datenbank anzuwenden, als unnötig hoch einstufen. Ich bleibe dennoch bei meiner Position der vorsichtigen Vermittlung zwischen den Welten und der Anbindung und Nutzung dort, wo es Sinn macht, und der Ablehnung dort, wo der Sinn zu fehlen scheint. Das Kapitel beginnt also mit einer Einführung in die Objektorientierung »für Dummies« und zeigt an einem konkreten Typ die aus meiner Sicht sinnvolle Verwendung. Der Code dieses Kapitels ist etwas länger als sonst üblich, zeigt aber auch mehrere Praktiken, nicht nur aus dem objektorientierten Umfeld, sondern auch bezüglich der Umsetzung in PL/ SQL. Kapitel 16: Integration von Oracle in Applikationen Dieses Kapitel untersucht die verschiedenen Szenarien, in denen Oracle in Datenbanken integriert wird. Wir sehen uns die verschiedenen Sperrverfahren im Code an und erläutern verschiedene Wege der Umsetzung. Anschließend kümmern wir uns darum, wie Daten einer externen Anwendung über das Netzwerk, aber auch über das Intra- oder Internet zur Verfügung gestellt werden kann. Die Idee hierbei ist, aufzuzeigen, dass Oracle sich nicht nur über direkte Datenbankverbindungen befragen lässt, sondern auch Möglichkeiten der losen Kopplung bietet, bei denen die Datenbank als REST- oder SOAP-basierter Webservice-Provider auftritt und so einen weiteren Zugriff auf die Daten der Datenbank gestattet. Bei Verbindungen über das lokale Netzwerk (ob nun direkt aus der Anwendung oder über einen Connection Pool eines Applikationsservers) zeige ich darüber hinaus, auf welche Weise Daten durch den Datenbankserver vorgehalten werden. Spannend wird diese Frage ja vor dem Hintergrund der enormen Datenmengen, die durch eine SQL-Anweisung eventuell über das Netzwerk geschoben werden können.

1.2.4

Teil 4: Workshops

Der abschließende Teil des Buches widmet sich der Abbildung konkreter Problemstellungen auf PL/SQL. Zum einen stelle ich eine Anwendungsarchitektur vor, die als Keimzelle für Ihre Projekte herangezogen werden kann, zum anderen zeige ich an einem horizontalen Dienst, auf welche Weise PL/SQL-Packages in Ihre Anwendungen integriert werden können.

26

1452.book Seite 27 Donnerstag, 5. August 2010 3:55 15

Danksagung

Kapitel 17: Workshop1 – Die Keimzelle sicherer Datenbankanwendungen Dieses Kapitel fasst viele der in den vorangegangenen Kapiteln besprochenen Techniken zu einer Architektur zusammen, in der die Datenbank die Rolle eines »Datenframeworks« übernimmt. Diesen Begriff habe ich mit Blick auf Java-Entwickler gewählt, weil dort für alles und jedes »Frameworks« verwendet werden. Mir geht es darum, aufzuzeigen, wie die wirklich staunen machenden Fähigkeiten der Oracle-Datenbank ideal genutzt werden können, um mit Bordmitteln und ein wenig Programmierung eine Datenbankarchitektur zu erzeugen, die ein Höchstmaß an Skalierbarkeit und Sicherheit mitbringt und sich dennoch ganz einfach in eine Anwendungsarchitektur einfügt. Dieses Kapitel ist eine Mischung aus SQL, Administrationswissen und PL/SQL und ist eigentlich insofern typisch für die Anwendungsentwicklung gegen Datenbanken, als eine optimale Lösung immer auch die intime Kenntnis der eingesetzten Technologien erfordert. Dieses Kapitel bietet sozusagen eine »Guided Tour« durch eine solche Datenbankanwendung und zeigt die Denkweise eines Entwicklers, der Oracle intensiv kennt und einsetzt. Kapitel 18: Workshop2 – Ein Logging-Package Das letzte Kapitel des Buches gibt ein Beispiel für ein komplettes Package für einen Einsatzzweck, der sich in jedem Projekt findet: ein Package für horizontale Dienste im Umfeld der Fehlerbehandlung und des Loggings. Als Keimzelle für ein entsprechendes Package für Ihre Projekte sollte dieses Projekt taugen. Die Highlights sind: Fehlermeldungen in beliebigen Sprachen, zentralisiertes Fehlerlogging, Logging kompatibel zum weitverbreiteten Java-Standard Log4J (entsprechende Implementierungen gibt es auch für andere Programmiersprachen) und damit die Fähigkeit, Fehlermeldungen der Datenbank in den normalen Fehlerbehandlungsfluss Ihrer Anwendung zu integrieren, und einiges mehr. Dieses Projekt versammelt in sich einen ganzen Strauß verschiedener Programmiertechniken: Objektorientierung, XML, ein witziges Datenmodell, Advanced Queueing und einiges mehr. Seien Sie also gespannt!

1.3

Danksagung

Meine Frau bat mich, in diesem Buch auf eine Danksagung nach der Art: »Ich danke meiner Familie, die mich viele Monate nicht zu Gesicht bekommen hat, für ihre Unterstützung« abzusehen, sondern – maximal – zu schreiben, dass, hätte sie mich nicht freundlich, aber bestimmt zur Arbeit gedrängt, das Buch immer noch nicht fertig sei … Meine Frau hat Spaß daran, und ich habe Spaß an meiner Frau, also lasse ich das natürlich auch mit der Danksagung.

27

1.3

1452.book Seite 28 Donnerstag, 5. August 2010 3:55 15

1

Einführung

Allerdings muss ich (weil es mir besonders wichtig ist) einen herzlichen Dank an meinen technischen Lektor, Joachim Zetzsche, aussprechen, der sich direkt und ohne zu zögern bereit erklärt hat, die Kapitel fachlich gegenzulesen und seine Anmerkungen zu Stil, Komplexität und Art der Darstellung einzubringen. Die Diskussion mit ihm über den Inhalt und den Aufbau dieses Buches haben mich enorm weitergebracht. Joachim ist einer der besten Kenner der Oracle-Datenbanktechnologie, den ich kenne, und mein Zutrauen, dass das, was ich über Oracle behaupte, der Wahrheit nahekommt, steigt steil, nachdem Joachim sein Plazet dazu gegeben hat. Herzlichen Dank dafür! Mein Dank gilt auch den übrigen Fachlektoren und Herrn Mattescheck von Galileo Press, der dieses Projekt betreut und Geduld mit mir hatte, als die Liefertermine von mir ein ums andere Mal verschoben wurden. Allerdings muss ich zu meiner Verteidigung auch sagen, dass die Aufgabe, neben dem täglichen Projektgeschäft ein so dickes Buch zu schreiben, brachial unterschätzt wird … Nicht zuletzt gilt mein Dank Ihnen, den Lesern, dafür, dass Sie sich die Zeit nehmen, dieses Buch zu lesen. Ich hoffe, Sie betrachten die investierte Zeit nicht als eine verlorene. Ich weiß, dass ich Ihnen da und dort erhebliche Konzentration abverlangen muss, tue das aber in dem Bewusstsein, dass die Inhalte, die ich dort vermittele, für die Programmierung guter Anwendungen unerlässlich sind. Die Aufgabe dieses Buches ist es, Ihnen zu erklären, wie man Oracle-Datenbanken richtig programmiert. Nicht irgendwie. Sollte Ihnen dieses Buch auf dem Weg zu solchen Anwendungen hilfreich sein, freue ich mich über eine Rückmeldung. Falls nicht – vielleicht senden Sie eine Mail an den Verlag? Nein, im Ernst, auch über Kritik freue ich mich, so sie denn konstruktiv ist und berücksichtigt, dass ich, sollte ich gescheitert sein, dies nicht mit Vorsatz getan habe.

28

1452.book Seite 395 Donnerstag, 5. August 2010 3:55 15

Die zentrale Aufgabenstellung für die Programmierung von PL/SQL ist der Umgang mit den Daten der Datenbank. PL/SQL ist für diese Aufgabe besser gerüstet als jede andere Programmiersprache im OracleUmfeld, denn als Erweiterung zu SQL setzt sie direkt auf der Datenbanksprache auf. Grund genug, diese Vorteile zu nutzen!

9

Das Arbeiten mit Daten

In Abschnitt 7.4, »Kollektionen in PL/SQL«, haben Sie bereits den grundsätzlichen Aufbau von Records, assoziativen Tabellen und so weiter kennengelernt. Dieses Kapitel vertieft nun dieses Wissen und stellt die einzelnen Datentypen in den Kontext von Anwendungen.

9.1

Strukturierte Variablen: Records und Typen

Beginnen wir mit den Records. Den grundsätzlichen Aufbau haben wir bereits besprochen, doch wo liegen Anwendungsbereiche über die Hauptanwendung, das Kopieren einer Tabellenzeile, hinaus?

9.1.1

Bindung an das Data Dictionary mit »%TYPE« und »%ROWTYPE«

Bei der Bindung an das Data Dictionary folgt unser Code den Änderungen am Datenmodell. So gut diese Fähigkeit im Allgemeinen ist, so hinterhältig kann sie aber auch sein, denn sie stößt bei bestimmen Rahmenbedingungen halt an Grenzen. Nehmen wir z.B. an, eine Tabelle wird durch eine neue Spalte erweitert. Dann wird dieser neuen Spalte natürlich in unserem Code niemals ein Wert zugewiesen, denn unser Code kennt diese Spalte nicht. Umgekehrt kann es sein, dass eine gelöschte Spalte einen Fehler auslöst, denn eine Zuweisung auf diese Spalte funktioniert nun natürlich nicht mehr. Doch haben wir in diesem Beispiel den großen Vorteil, davon zu erfahren, denn nun kompiliert die Prozedur nicht mehr. Machen wir uns dies an einem Beispiel klar. Ich hatte unserer Tabelle dept eine Spalte max_sal hinzugefügt, um einen schnellen Ausweg aus einem Mutating-Table-Problem zu erhalten (siehe Abschnitt

395

1452.book Seite 396 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

8.3.5, »Trigger und Datensichten (INSTEAD-OF-Trigger)«). Vielleicht habe ich mich nun doch entschlossen, einen anderen Weg zu verwenden, denn mir ist erst jetzt klar geworden, dass die zusätzliche Spalte das Problem eigentlich gar nicht gelöst, sondern nur verschoben hat: Wie pflege ich denn jetzt das Maximum der Gehälter in der Tabelle dept, wenn konkurrierend die Gehälter der Benutzer in Tabelle emp erhöht werden? Daher benötige ich diese Spalte nicht mehr. Leider habe ich eine Prozedur, die dieser Spalte einen Wert zugewiesen hat. Diese Zuweisung gelingt nun natürlich nicht mehr. Doch wo war dieser Code noch einmal? Irgendwo in unserem Code wird eine Zeile etwa dieser Art stehen: declare dept_rec dept%ROWTYPE; begin … dept_rec.max_sal := max_sal; …

Diese Zeile wird vom Compiler nicht mehr kompiliert, denn der Record dept_rec enthält keine Struktur mit dem Namen max_sal mehr. Nur zur Verdeutlichung: Hätten wir den Record explizit deklariert und nicht an das Data Dictionary gebunden, wäre dieser Fehler nicht aufgefallen, sondern zur Laufzeit aufgetreten. Die eigentliche Kunst für Oracle liegt aber gar nicht so sehr im Kompilieren dieser Struktur, sondern darin, zu erkennen, dass irgendeine Änderung am Data Dictionary genau diese Zeile Code ungültig macht. Denn zum Zeitpunkt des Kompilierens existierte die Spalte noch in der Tabelle dept, die Spalte wurde erst gelöscht, nachdem dieser Code kompiliert war. Dennoch erkennt Oracle selbsttätig, dass diese Struktur nicht mehr gültig ist, weil sich die Voraussetzungen geändert haben. Im konkreten Fall setzt Oracle den Status dieser Prozedur auf den Status invalid und erlaubt die Ausführung nicht mehr. Sie erkennen also sofort, dass ein Problem vorliegt, und können es anschließend lösen. Die Verwaltung dieser Abhängigkeiten durch Oracle ist es, wovon Sie auch in diesem Beispiel profitieren. Doch auch an diesem Beispiel können wir uns klarmachen, dass es keine Vorteile ohne Nachteile gibt. Wir profitieren also von der Verwaltung der Abhängigkeit durch Oracle, weil die Deklarationen aufeinander aufbauen. Denken wir dieses Thema aber weiter, so wird klar, dass die Änderung einer zentralen Datenstruktur eventuell eine kaskadierende Kette von Neukompilierungen nach sich ziehen kann. Oracle bezeichnet so etwas als Abhängigkeitskette (dependency chain). Als Beispiel nehmen wir ein Package mit Konstanten an, das von vielen anderen Packages referenziert wird. Ändere ich nun dieses zentrale Package, wird es

396

1452.book Seite 397 Donnerstag, 5. August 2010 3:55 15

Strukturierte Variablen: Records und Typen

ungültig und mit ihm alle auf der Deklaration aufbauenden Packages, Prozeduren und Funktionen. Eine Anpassung eines zentralen Packages hat also das Neukompilieren vieler weiterer Packages zur Folge. Je nach Anwendungssituation kann dies ein Nachteil sein. Besonders ärgerlich ist dieses Neukompilieren, wenn es bei laufender Datenbank durchgeführt werden soll. Denn in diesem Fall ist es sehr wahrscheinlich, dass Packages rekompiliert werden müssen, die von anderen Benutzer gerade verwendet werden. Diese Packages sind dann gesperrt, werden entsprechend nicht kompiliert, und ein Patch kann gefährdet sein. Aber es gibt noch feinere Probleme. Was ist zum Beispiel, wenn Sie die zulässige Länge einer Spalte beschränken? Vorher haben Sie 30 Zeichen erlaubt, nun nur noch 25? Die Folgen von Änderungen dieser Art können von Oracle nicht immer korrekt ausgewertet werden. Natürlich ist es möglich, einer Variablen den Wert einer anderen Variablen mit großzügigeren Grenzen zuzuordnen, solange die maximale Länge der Variablen, der ein Wert zugewiesen wird, nicht überschritten wird: SQL> declare 2 a varchar2(10 char); 3 b varchar2(20 char) := 'Peter'; 4 begin 5 a := b; 6 end; 7 / PL/SQL-Prozedur erfolgreich abgeschlossen. Listing 9.1 Beispiel für eine mögliche Variablenzuweisung

Es kann also sein, dass eine Verkürzung der Spaltenbreite für Oracle unproblematisch erscheint, dann aber zur Laufzeit Fehler auslöst, weil eine andere Variable immer noch von der breiten Spalte ausgeht. Im Gegensatz dazu ist es im Regelfall unproblematisch, Datentypen zu erweitern. Eventuell können Sie von den erweiterten Möglichkeiten nicht vollständig profitieren, ohne Ihren Code anzupassen, doch grundsätzlich sollten in dieser Konstellation keine Fehler auftauchen. Ein anderer Problembereich ist die Änderung des Datentyps. Was geschieht, wenn eine Spalte, die vorher vom Typ varchar2 war, nun in den Typ date umgewandelt wird? Sie sagen, dass so etwas passiere, sei doch wohl sehr unwahrscheinlich? Ich weiß nicht, wie viele Datenmodelle ich schon gesehen habe, die Datumsangaben als Zeichenketten speichern und im Zuge eines Redesigns endlich auf den Typ Datum umstellen! Oracle wird versuchen, solange wie möglich mit impliziten Umwandlungen den Code »am Leben zu erhalten«, doch sind dem natürlich Grenzen gesetzt. Je nach Art der Überschreitung kann eine solche

397

9.1

1452.book Seite 398 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

Grenze automatisch erkannt werden, zum Teil aber auch nicht. Allerdings gilt natürlich auch hier: Implizite Konvertierungen sollten Sie in Ihrem Code nicht tolerieren. Manchmal ist dies zwar kaum sichtbar (etwa bei einer Schleifenvariable, die vom Typ pls_integer ist und, wenn sie einer Variable vom Typ number zugeordnet wird, konvertiert werden muss), doch in jedem Fall ist es schlechter Programmierstil, etwa auf eine Standardumwandlung von Datumszeichenketten in ein Datum zu hoffen. Wo immer dies unumgänglich ist, sollten Sie die Datentypen explizit ineinander umwandeln. Insgesamt gilt jedoch: Binden Sie Ihre Records an das Data Dictionary, wo immer dies möglich ist. Die Robustheit Ihres Codes nimmt zu, außerdem kommunizieren Sie klarer, was der Code eigentlich tun soll: declare l_empno emp.empno%type; dept_rec dept%rowtype; begin … end;

Bei dieser Variablen müssen Sie nicht lange überlegen, welche Information in ihr wohl gespeichert werden soll. Ebenso gilt dies für die Deklaration der Recordvariablen eine Zeile tiefer. Code dieser Art dokumentiert sich also selbst. Die Bindung an das Data Dictionary kann aber auch auf andere Weise als über die Bindung an eine Tabelle erfolgen. Eine gute Möglichkeit ist die Bindungen an die Definition einer Datenbanksicht oder an einen Cursor. Durch diese Möglichkeiten können wir sehr gut steuern, welche Informationen unser Record enthalten soll und welche nicht.

9.1.2

Insert- und Update-Anweisungen mit Records

Records können im Umfeld von Insert- oder Update-Anweisungen dazu genutzt werden, Daten »in einem Rutsch« in die Tabellen zu integrieren. Sehen wir uns dazu einige einfache Beispiele an. Im folgenden Beispiel wird ein Record mittels des %ROWTYPE-Attributs definiert und anschließend mit Werten für eine neue Zeile gefüllt. Beachten Sie, dass der Aufruf der Sequenz departments_ seq.nextval in Zeile 4 in dieser direkten Form erst ab Version 11g möglich ist. In Oracle 10g müssten Sie eine Variable deklarieren und die Sequenz über eine Select-Anweisung in die lokale Variable umkopieren: SQL> declare 2 dept_rec departments%rowtype; 3 begin 4 dept_rec.department_id := departments_seq.nextval;

398

1452.book Seite 399 Donnerstag, 5. August 2010 3:55 15

Strukturierte Variablen: Records und Typen

5 dept_rec.department_name := 'Accounting'; 6 dept_rec.manager_id := null; 7 dept_rec.location_id := 2700; 8 insert into departments values dept_rec; 9 end; 10 / PL/SQL-Prozedur erfolgreich abgeschlossen. SQL> select * 2 from departments 3 where location_id = 2700; DEPARTMENT_ID DEPARTMENT_NAME MANAGER_ID LOCATION_ID ------------- ------------------------ ---------- ----------70 Public Relations 204 2700 280 Accounting 2700 Listing 9.2 Insert-Anweisung mittels eines Records

Ähnlich komfortabel ist die Integration eines Records in Update-Anweisungen. Vorab sollten Sie beachten, dass die einfach zu schreibende und zu benutzende Update-Variante mittels %ROWTYPE alle Spalten ins Update nimmt, insbesondere auch die Primärschlüsselspalten, ob sich deren Inhalt nun ändert oder nicht. Dies hat zur Folge, dass eventuell referenziell abhängige Tabellen gesperrt werden müssen, wenn deren Fremdschlüsselspalte nicht indiziert ist. (Zur Begründung und Lösung dieses Problems siehe Abschnitt 4.3.2, »Performanzüberlegungen zu Datenbank-Constraints«). Zudem können Trigger ausgelöst werden, obwohl keine relevante Spalte ihren Wert ändert. (Dieses Problem hatten wir in Abschnitt 8.1.1, »Anweisungs- versus Zeilentrigger«, besprochen). Aber sehen wir uns trotz dieser Warnhinweise diese Variante an: SQL> declare 2 dept_rec departments%ROWTYPE; 3 begin 4 dept_rec.department_id := 280; 5 dept_rec.department_name := 'Administration'; 6 dept_rec.location_id := 2700; 7 update departments 8 set row = dept_rec 9 where department_id = 280; 10 end; 11 / PL/SQL-Prozedur erfolgreich abgeschlossen.

Sie erkennen die Pseudospalte row in Zeile 8. Diese Pseudospalte ist lediglich links des Gleichheitszeichens und hinter der (dann einzigen) set-Klausel erlaubt.

399

9.1

1452.book Seite 400 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

Alle Werte, die vorher im Record nicht belegt wurden, werden durch Null-Werte ersetzt. Wenn Sie die Kontrolle über die Spalten, die aktualisiert werden sollen, behalten möchten, können Sie auch folgende Variante schreiben, die etwas länger ist, dafür aber gezielter agiert: SQL> declare 2 3

dept_rec departments%ROWTYPE; begin

4

-- Lies einen Datensatz in den Record

5

select *

6

into dept_rec

7

from departments

8

where department_id = 280;

9

-- Simuliere Datenänderungen durch den Anwender

10

dept_rec.department_name := 'Accounting';

11

-- Schreibe die geänderten Daten in die Datenbank

12

update departments

13

set department_name = dept_rec.department_name,

14

location_id = dept_rec.location_id,

15

manager_id = dept_rec.manager_id

16

where department_id = dept_rec.department_id;

17

end;

18

/

PL/SQL-Prozedur erfolgreich abgeschlossen. SQL> select * 2 3

from departments where department_id = 280;

DEPARTMENT_ID DEPARTMENT_NAME

MANAGER_ID LOCATION_ID

------------- ------------------------ ---------- ----------280 Accounting

2700

Listing 9.3 Update-Anweisung mittels eines Records

Hier sehen Sie zudem, wie wir einen Datensatz aus der Datenbank lesen, ein Attribut ändern und den geänderten Wert in die Datenbank zurückschreiben. Dies ist natürlich verkürzt, aber wir können uns eine Dialoganwendung vorstellen, die einen Record aus der Datenbank liest, an ein Frontend gibt, den geänderten Record zurückerhält und anschließend in die Datenbank einliest. Gleichzeitig behalten wir bei diesem Prozess die volle Kontrolle darüber, welche Spalte aktualisiert werden soll oder nicht.

400

1452.book Seite 401 Donnerstag, 5. August 2010 3:55 15

Strukturierte Variablen: Records und Typen

9.1.3

Verwendung explizit deklarierter Records

Alle bisherigen Beispiele haben die Deklaration des Records in der ein oder anderen Form an das Data Dictionary gebunden, sei es über das Attribut %ROWTYPE oder über das Attribut %TYPE. Dies muss natürlich nicht so sein. Wenn Sie einen Record explizit selbst deklarieren möchten, erinnert die syntaktische Form sehr an die Definition einer Tabelle: SQL> 2 3 4 5 6 7 8 9 10

declare type my_rec is record ( id number not null := 0, description varchar2(200 char), content xmltype); rec_var my_rec; begin < irgendeine Aktion … > end; /

Listing 9.4 Deklaration eines Records

Sie sehen, dass alle Einschränkungen, die wir für normale Variablen vornehmen können, auch in Records erlaubt sind (allerdings keine Konstanten). Objektorientierte Entwickler entdecken in diesen Records vielleicht einen Struct wieder, aber auch außerhalb dieser Denkwelt sind Records praktische Strukturen, um z.B. die Anzahl der Parameter zu reduzieren, die an eine Prozedur übergeben oder von dort zurückerhalten werden. Leider ist aber die Übergabe eines Records an eine Prozedur nicht ohne Weiteres möglich: Der Record muss außerhalb der Prozedur bekannt sein, damit die aufrufende Anweisung eine entsprechende Struktur erzeugen oder entgegennehmen kann. Ein Record kann aber lediglich innerhalb von PL/SQL definiert werden, ein create type my_rec is record… existiert in SQL nicht. Daher muss der Record im Rahmen eines Packages definiert und so »von außen« zugänglich gemacht worden sein. Die Programmierung mit Records als Parameter von Prozeduren oder Funktionen setzt also ein Package voraus. Sehen wir uns ein kurzes Beispiel für eine solche Konstruktion an. In unserem Beispiel möchten wir eine strukturierte Information übergeben, um im Rahmen einer Autorisierung einige Angaben zur Validierung zu übergeben. Wir möchten, dass eine Anmeldung einen korrekten Zeitstempel, einen Programmnamen und einen Versionsstring übergibt. Anhand dieser Informationen können wir erkennen, welches Programm die Autorisierung bei der Datenbank beantragt und in welcher Version dieses vorliegt. Sie könnten sich vorstellen, dass wir eine solche Informa-

401

9.1

1452.book Seite 402 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

tion in Kombination mit einem Benutzernamen und einem Passwort verwenden können, um uns an einer Anwendung anzumelden. Da ich das Beispiel einfach halten möchte, verzichte ich derzeit auf das Passwort und den Benutzernamen. Erstellen wir also zunächst ein Package: SQL> create or replace package pkg_authorization 2 as 3 type app_rec_t is record ( 4 app_name char(5 char), 5 app_version char(5 char), 6 time_stamp date); 7 8 function authorize(app_rec in app_rec_t) 9 return boolean 10 ; 11 end pkg_authorization; 12 / Package wurde erstellt. SQL> create or replace package body pkg_authorization 2 as 3 function authorize(app_rec in app_rec_t) 4 return boolean 5 as 6 two_minutes constant number := 2/1440; 7 begin 8 return app_rec.app_name = 'HDMAP' 9 and app_rec.app_version = '1.0.0' 10 and app_rec.time_stamp between sysdate - two_minutes and sysdate + two_minutes; 11 end authorize; 12 end pkg_authorization; 13 / Package Body wurde erstellt. SQL> set serveroutput on SQL> declare 2 app_rec pkg_authorization.app_rec_t; 3 begin 4 app_rec.app_name := 'MY_AP'; 5 app_rec.app_version := '1.0.0'; 6 app_rec.time_stamp := sysdate; 7 if pkg_authorization.authorize(app_rec) 8 then

402

1452.book Seite 403 Donnerstag, 5. August 2010 3:55 15

Strukturierte Variablen: Records und Typen

9 dbms_output.put_line('Autorisiert'); 10 else 11 dbms_output.put_line('Nicht autorisiert'); 12 end if; 13 end; 14 / Autorisiert PL/SQL-Prozedur erfolgreich abgeschlossen. Listing 9.5 Deklaration eines Records in einem Package

Sie erkennen die Deklaration des Recordtyps in der Package-Spezifikation. Anschließend wird eine Instanz des Records als Eingabeparameter der Funktion authorize vereinbart, indem die Variable an die Deklaration des Records im Package gebunden wird. Dies ist natürlich der Grund dafür, dass die RecordDeklaration in der Package-Spezifikation vorgenommen werden musste, ansonsten wäre sie ja nicht sichtbar. Innerhalb der Prozedur authorize wird der übergebene Parameter sozusagen »ausgepackt« und werden die einzelnen Bestandteile mit vorgegebenen Werten verglichen. Das Ergebnis dieser Prüfung wird anschließend als Wahrheitswert zurückgeliefert. Mithilfe dieser Technik ist nur ein Parameter zu übergeben anstatt von drei zusammengehörigen Informationen. Dadurch wird Ihr Code besser lesbar, zudem haben Sie eine leicht zu verarbeitende, selbsterklärende Struktur. Eines geht allerdings auch mit dieser Art der Deklaration nicht: Ein Record wird niemals direkt in SQL zu benutzen sein. SQL kennt keine Variablen, sondern maximal objektorientierte Typen, die für ähnliche Zwecke gebraucht werden können. Wenn Sie sich die Packages ansehen, die von Oracle mitgeliefert werden, stellen Sie allerdings fest, dass diese Art der Programmierung von Oracle selbst nicht allzu häufig umgesetzt wird. Hier herrschen immer noch Prozeduren mit vielen Parametern vor. Auf der Habenseite der herkömmlichen Art der Programmierung steht sicherlich, dass zum Aufruf der Prozedur kein Record erzeugt werden muss. Diese zusätzliche Komplexität mag einer einfachen Bedienung im Weg stehen. Zudem wird die Anzahl der Records, die Sie in einem umfangreichen Package deklarieren müssen, doch recht hoch sein, zumal Sie einen Record für jede überladene Prozedur definieren müssten. Auf der anderen Seite profitieren Sie von kürzeren Funktionsaufrufen und möglicherweise klarerem Code. Letztlich ist es eine Stilfrage; funktionale Unterschiede sehe ich nicht. Beurteilen Sie also selbst, ob Sie diese Art der Programmierung mögen oder nicht. Ich entscheide mich tendenziell so: Prozeduren, die von Code außerhalb der Datenbank aufgerufen werden, versehe ich eher mit solchen Records als Prozeduren, die innerhalb der Datenbank aufgerufen werden. Das heißt, dass ich Prozeduren, die

403

9.1

1452.book Seite 404 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

ich benötige, um einer Anwendung in Java oder C# oder was auch immer eine API zur Änderung meiner Daten anzubieten, als externes Interface gerne schlank halten möchte. Gerne verwende ich für solche Parameter auch XML, wenn es passt, sodass eher eine nachrichtenartige Struktur beim Aufruf dieser Funktionen resultiert. Allerdings ist das lediglich meine persönliche Auffassung.

9.1.4

Verwendung der Returning-Klausel mit Records

Bei jedem Insert oder Update lassen sich im gleichen Round-Trip zum Server auch einige Spalten über die Returning-Klausel zurückliefern. Sehen wir uns in einem Beispiel an, wie eine Returning-Klausel einer SQL-Anweisung im Zusammenhang mit einem Record genutzt werden kann. Die Returning-Klausel erlaubt es uns, nach einer DML-Anweisung eine oder mehrere Spaltenwerte zurückzuliefern. Wenn wir mehrere Spalten benötigen, können wir zur Übergabe gut einen Record verwenden. Diesen müssen wir so deklarieren, dass er alle Spalten aufnehmen kann, die durch die Returning-Klausel geliefert werden. Daher können wir den Record nicht an die Definition der Tabelle binden, denn die Tabelle enthält zu viele Spalten. In unserem Beispiel wollen wir die Bewegung der Gehälter in einer Protokolltabelle hinterlegen. Dazu erstellen wir zunächst eine Tabelle, die diese Informationen aufnehmen kann: SQL> create table emp_log as 2 select * 3 from emp 4 where 1=0; Tabelle wurde erstellt. SQL> alter table emp_log add change_action varchar2(1 char); Tabelle wurde geändert. SQL> alter table emp_log add change_user varchar2(30 byte); Tabelle wurde geändert. SQL> alter table emp_log add change_date date; Tabelle wurde geändert.

Dann benötigen wir noch eine Prozedur, mit deren Hilfe wir die Gehälter anheben (oder absenken) können. Diese Prozedur soll gleichzeitig auch die Einträge in die Protokolltabelle vornehmen. Auf diese Weise ersparen wir uns einen Trigger auf die Tabelle emp. Wir können uns die folgende Prozedur vielleicht als Teil einer Mitarbeiter-Wartungs-API vorstellen: SQL> create or replace 2 procedure raise_sal( 3 emp_id in emp.empno%type, 4 raise_factor in number := 1)

404

1452.book Seite 405 Donnerstag, 5. August 2010 3:55 15

Strukturierte Variablen: Records und Typen

5 6 7 8 9 10 11 12 13 14 15 16 17

as

type emp_rec_t is record ( ename emp.ename%TYPE, sal emp.sal%TYPE); emp_rec emp_rec_t; begin update emp set sal = sal * raise_factor where empno = emp_id returning ename, sal into emp_rec; if SQL%ROWCOUNT > 0 then insert into emp_log (empno, ename, sal, change_action, change_user, change_date) 18 values (emp_id, emp_rec.ename, emp_rec.sal, 'U', user, sysdate); 19 end if; 20 end; 21 / Prozedur wurde erstellt. Listing 9.6 Beispiel für einen Record in einer Returning-Klausel

Beachten Sie, wie die aktualisierten Informationen durch die Returning-Klausel zurückgeliefert und in der nächsten Insert-Anweisung verwendet werden. Damit diese Art der Zuweisung funktioniert, muss der Record selbstverständlich positional exakt so definiert werden, wie die Werte in der Returning-Klausel geliefert werden – sowohl von der Anzahl als auch vom Datentyp her. Das heißt, dass die Returning-Klausel in unserem Beispiel zwei Record-Attribute erwartet und dass das erste Attribut ein ausreichend großer Varchar2-Datentyp und das zweite Attribut ein Number-Datentyp sein muss. Die Datenbank kümmert sich allerdings nicht um die Bezeichnungen der Record-Strukturen und wird auch Datentypen umwandeln, falls das möglich ist. Eine Erwähnung verdient vielleicht noch die Zeile 15. Dort wird der Cursor SQL daraufhin geprüft, wie viele Zeilen er bearbeitet hat. Der Cursor SQL ist ein Bezeichner für den implizit von Oracle genutzten Cursor, um die Update-Anweisung auszuführen. Hier wird das Cursorattribut ROWCOUNT verwendet, das die Anzahl der verarbeiteten Zeilen enthält. Sollte eine ungültige Mitarbeiter-ID übergeben worden sein, führt die Update-Anweisung keine Änderung aus, und es wird auch kein Datensatz in die Logtabelle geschrieben. Sehen wir uns die Returning-Klausel abschließend für eine Update-Anweisung an:

405

9.1

1452.book Seite 406 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

SQL> declare 2 type emp_rec_type is record ( 3 last_name employees.last_name%TYPE, 4 salary employees.salary%TYPE); 5 emp_rec emp_rec_type; 6 begin 7 update employees 8 set salary = salary * 1.05 9 where employee_id = 106 10 returning last_name, salary into emp_rec; 11 -- Ausgabe mit returnierten Werten erzeugen 12 dbms_output.put_line( 13 'Das Gehalt für Mitarbeiter ' || emp_rec.last_name || 14 ' beträgt nun Taler ' || emp_rec.salary); 15* end; Das Gehalt für Mitarbeiter Pataballa beträgt nun Taler 5040 PL/SQL-Prozedur erfolgreich abgeschlossen. Listing 9.7 Returning-Klausel in einer Update-Anweisung

9.1.5

Alternative zum Record: Objekt

Als Alternative zum Record ist auch ein selbst definierter Datentyp denkbar, denn dieser Typ kann ebenfalls mehrere unterschiedliche Datentypen zu einem Konstrukt zusammenfassen. Mit diesem Typ machen wir den Schritt in die Objektorientierung, die seit Version 8 langsam, aber unaufhaltsam Einzug in die Oracle-Datenbank gehalten hat. Der Fokus dieses Abschnittes ist es aber nicht, diese Technik im Detail zu beschreiben, daher soll nur ein kurzes Beispiel für die Verwendung eines simplen Typs gegeben werden, und zwar insofern, als sich dessen Verwendung mit der eines Records deckt. Zur Deklaration eines Typs wird eine SQL-Anweisung verwendet, dieser Typ ist also ein Datenbankobjekt und mithin schemaweit sichtbar (mindestens, denn die Sichtbarkeit kann, wie bei jedem anderen Datenbankobjekt auch, über Grant-Anweisungen an andere Benutzer erweitert werden). So ist dann die schlichte Verwendung als RecordErsatz etwas aufwendiger in der Definition, bringt aber eben auch keine wesentlichen Vorteile gegenüber einem Record, sondern erfordert neben der externen Deklaration auch noch den Aufruf der Konstruktormethode (), um eine Instanz dieses Typs zu erstellen: SQL> -- In SQL: SQL> create type my_type is object( 2 name varchar2(80 char), 3 job varchar2(30 char)); 4 / Typ wurde erstellt.

406

1452.book Seite 407 Donnerstag, 5. August 2010 3:55 15

PL/SQL-Kollektionen

Achten Sie darauf, dass SQL*Plus das abschließende Zeichen »/« verlangt, wenn Sie ein Objekt deklarieren. SQL> set serveroutput on SQL> declare 2 local_type my_type; 3 begin 4 local_type := my_type('MÜLLER', 'REVISOR'); 5 dbms_output.put_line(local_type.job); 6 end; 7 / REVISOR PL/SQL-Prozedur erfolgreich abgeschlossen. Listing 9.8 Objekt als Record-Alternative

In dieser simplen Variante ist der objektorientierte Typ keine Alternative zum Record. Er wird hier eher der Vollständigkeit halber erwähnt. Weitere Informationen finden Sie in Kapitel 15, »Objektorientierung«, wo ich diesen Typ nicht nur genauer erklären, sondern auch bestechendere Einsatzszenarien zeigen werde. Ein Vorteil ist allerdings schon hier sichtbar: Ein Objekt ist in SQL sichtund benutzbar, ein Record als PL/SQL-Variable nicht!

9.2

PL/SQL-Kollektionen

Nachdem wir uns in Abschnitt 7.4, »Kollektionen in PL/SQL«, bereits mit den Grundlagen von Kollektionen vertraut gemacht haben, folgen nun einige weiterführende Beispiele und Anwendungsbereiche.

9.2.1

Verwendung von assoziativen Tabellen

Die erste Gruppe von Kollektionen stellen die assoziativen Tabellen dar. Diese Strukturen, die nur in PL/SQL eingesetzt und nicht in der Datenbank gespeichert werden können, sind im Grunde Tabellen mit einem Schlüssel- und einem Nutzwert. Der Schlüsselwert dient ausschließlich dazu, einen Nutzwert in der assoziativen Tabelle wiederzufinden. Er muss daher eindeutig sein und kann entweder eine Zahl oder eine Zeichenkette sein. Sie definieren ein solches assoziatives Array wie folgt: SQL> declare 2 type name_tab is table of emp.ename%type 3 index by binary_integer; 4 begin

407

9.2

1452.book Seite 408 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

5 6 7

… end; /

In diesem Beispiel habe ich als Schlüsselwert eine Zahl verwendet. PL/SQL definiert hier den Datentyp binary_integer, der Ganzzahlen zwischen –2 147 483 648 und 2 147 483 647 erlaubt (32 Bit) und im Übrigen mit dem Datentyp pls_integer synonym ist. Im Beispiel ist es naheliegend, als Schlüsselwert für die Tabelle die Mitarbeiternummer aus der Spalte empno zu verwenden, was insofern eine gute Idee ist, als damit direkt auch klar wird, dass die Schlüsselwerte durchaus nicht bei 1 beginnen und – wie ein Index – hochgezählt werden müssen, sondern beliebig gewählt werden können. Als Nutzwert habe ich hier eine Zeichenkette (den Nachnamen des Mitarbeiters) gewählt, aber auch das muss nicht so sein. Sie können beliebige Datentypen verwenden und insbesondere auch einen Record. Damit ergibt sich eine Datenstruktur, die im Notfall eine ganze Tabelle aufnehmen könnte, wie das folgende Beispiel zeigt: SQL> 2 3 4 5 6 7

declare type emp_tab is table of emp%rowtype index by binary_integer; begin … end; /

Listing 9.9 Einfache assoziative Tabellen

Durch diese Deklaration könnte sich also endlich ein Weg ergeben, mit ganzen Tabellendaten auf einmal arbeiten zu können. Doch ist diese Möglichkeit wahrscheinlich nicht der beste Weg, denn Sie müssen im Hinterkopf behalten, dass die Daten eines Records physikalisch in den Arbeitsspeicher umkopiert werden. Bei sehr großen Tabellen ist das sicherlich keine gute Idee. Besser wäre es, große Datenmengen lediglich zu referenzieren und dort zu lassen, wo sie ohnehin bereits existieren, auf der Platte oder im Hauptspeicher der Datenbank nämlich. Diese Option steht uns mit den Cursorn zur Verfügung und soll dort auch besprochen werden. Wenn diese Anwendung also nicht sinnvoll ist, wofür benötigen wir dann assoziative Tabellen? Einerseits ist ihr oben genannter Nachteil auch ein entscheidender Vorteil: Da die assoziativen Tabellen die Daten lokal vorhalten, entfällt (eventuell) der Netzwerk- und Festplattenplatz, den die Daten benötigten, wären sie in Tabellen gespeichert. Zudem können Sie diese Strukturen in Packages deklarieren und initial mit Daten füllen, die für die Dauer der Session genutzt werden sol-

408

1452.book Seite 409 Donnerstag, 5. August 2010 3:55 15

PL/SQL-Kollektionen

len. Dadurch entfällt das andauernde Nachladen der Daten. Ideal ist diese Datenstruktur also dort, wo eine geringere Datenmenge lokal vorgehalten und schnell verfügbar gemacht werden muss. Natürlich muss zudem sichergestellt sein, dass diese Daten während der Dauer der Benutzung nicht angepasst werden müssen, falls die zugrunde liegenden Daten sich ändern sollten. Ich verwende diese Strukturen zum Beispiel gern in Packages, um Startwerte initial zu laden. Stellen Sie sich vielleicht eine Liste von Währungskursen vor. Für unser Beispiel soll es ausreichen, dass die Umrechnungskurse der Europäischen Zentralbank zugrunde gelegt werden, die von der Bank einmal täglich veröffentlicht werden. Diese Aktion ist natürlich zeitlich aufwendig, da die Kurse über eine entfernte Ressource geladen werden müssen. Andererseits sind nicht viele Kurse zu laden, sodass es sich anbietet, die Daten lokal vorzuhalten und nur nachzuladen, wenn sie älter als einen Tag sind. Die Implementierung dieses Beispiels werde ich nachholen, wenn ich Ihnen die objektorientierten Fähigkeiten der Datenbank genauer vorstelle. Dann sind assoziative Tabellen perfekt geeignet, um eine Menge von Datenbankzeilen im Code zu berechnen und anschließend in einer Bulk-Operation an die Datenbank zu übergeben. Da diese Verwendung sehr häufig geschieht, stelle ich sie im folgenden Abschnitt gesondert vor.

9.2.2

Massenverarbeitung mit assoziativen Tabellen

In Abschnitt 4.8, »Beispiel zum Einfluss der Programmierung«, habe ich in einem etwas fiktionalen Szenario den großen Einfluss der Programmierstrategie auf die Performanz und Skalierbarkeit der Anwendung gezeigt. Eine Kernaussage des Kapitels war, dass Datenbanken mengenorientiert und nicht satzweise programmiert werden sollten. Das Beispiel verwendete folgenden Code-Ausschnitt, um eine mengenorientierte Programmierung zu realisieren: SQL> create or replace procedure SQL_performance_test_5 2 as 3 type value_table_type is table of pls_integer 4 index by binary_integer; 5 value_table value_table_type; 6 iterations integer := 10000; 7 begin 8 for i in 1..iterations loop 9 value_table(i) := i; 10 end loop; 11 forall indx in 1 .. iterations 12 insert into test_table values(value_table(indx)); 13 commit;

409

9.2

1452.book Seite 410 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

14 15

end; /

Listing 9.10 Verwendung einer assoziativen Tabelle in Bulk-Anweisungen

Mit dem bislang aufgebauten Wissen über PL/SQL können wir diesen Code nun deutlich besser verstehen: Wir erzeugen eine assoziative Tabelle value_table_ type, von dem wir die Variable value_table ableiten. Anschließend kopieren wir die Zahlen von 1 bis 10.000 in diese assoziative Tabelle. Wir wissen nun, dass diese Daten mithin nicht in die Datenbank, sondern im Arbeitsspeicher gespeichert werden (müssen, das vermerken wir hier direkt als Nachteil dieser Methode). Anschließend wird die assoziative Tabelle als Ganzes der InsertAnweisung übergeben, die anschließend die Werte in einem Rutsch in die Datenbanktabelle einfügt. Inhaltlich entsteht folgender Pseudocode: insert into test_table select * from value_table; Listing 9.11 Pseudocode einer Bulk-Anweisung

Die entscheidende Anweisung ist die Forall-Anweisung in Zeile 11. Sehen wir uns diese Anweisung etwas genauer an. Auch wenn der Eindruck erweckt wird, ist die Forall-Anweisung keine Schleife, sondern eine Anweisung, die dazu dient, den übergebenen Parameter in Form einer SQL-Anweisung als dynamisches SQL auszuführen und dabei in sinnvoller Weise die übergebenen Parameterwerte zu binden. Die Verwendung dieser Anweisung erfordert eine gewisse Vorarbeit, denn die einzufügenden Parameter müssen als Kollektion vorliegen, in unserem Fall als assoziative Tabelle, es geht aber auch eine geschachtelte Tabelle. Im Fall einer assoziativen Tabelle funktionieren allerdings lediglich solche mit einem pls_integer-Schlüsselwert, nicht jedoch solche mit einem varchar2-Schlüssel. Zudem existieren einige Einschränkungen bezüglich des SQLs und der Referenz auf die Schlüsselwerte, die sich vielleicht so zusammenfassen lassen: 왘 Verwenden Sie ein SQL, das so einfach wie irgend möglich ist. 왘 Verweisen Sie auf die Indizes lediglich in einfacher (und nicht berechneter) Form, sagen Sie also value_table(indx) und nicht value_table(indx+1). 왘 Verwenden Sie eine Kollektion nicht sowohl in der Spaltenliste einer UpdateAnweisung als auch in der Where-Klausel der Update-Anweisung. Die konkreten Einschränkungen variieren mit der Datenbankversion und beziehen sich auch auf Randbereiche wie z.B. spärlich besetzte Kollektionen etc. Zum

410

1452.book Seite 411 Donnerstag, 5. August 2010 3:55 15

PL/SQL-Kollektionen

tieferen Verständnis dieser Einschränkungen möchte ich gern auf die OnlineDokumentation (PL/SQL Language Guide, FORALL-Statement) verweisen, denn sie sind zum Teil recht speziell und Erläuterungen dazu würden den Rahmen des Buches definitiv sprengen. In dieser einfachen Form wie im Beispiel oben haben wir einen hohen Preis für die Optimierung der Insert-Anweisung gezahlt, denn wir müssen immerhin alle 10.000 Zeilen im Arbeitsspeicher vorhalten. In der Praxis wird so etwas eher selten gemacht, denn die Optimierung stellt sich als Balance zwischen zwei widerstrebenden Anforderungen dar, wie in Abbildung 9.1 schematisch dargestellt ist: Auf der einen Seite soll der Durchsatz maximal, auf der anderen Seite aber der Arbeitsspeicherbedarf minimal sein. Bei meinen Untersuchungen zu diesem Thema bin ich auf folgenden, groben Zusammenhang gestoßen: Die Optimierungseffekte sind bereits bei relativ kleinen Bulkgrößen sehr deutlich spürbar und nehmen bei größeren Bulkgrößen nicht linear zu, sondern steigen zunehmend langsamer. So gibt es also ein Optimum, das von vielen Faktoren abhängt, aber bei meinen Szenarien, die ich getestet habe, bereits bei wenigen 100 Zeilen pro Bulk absolut akzeptable Ergebnisse erzielte. Ich gehe sicher davon aus, dass die Zeilenlänge eine ebenso wesentliche Rolle spielt wie die gesamte zur Verfügung stehende Infrastruktur (Arbeitsspeicher, Prozessorgeschwindigkeit und -anzahl, Netzwerk- und Plattengeschwindigkeit etc.), daher möchte ich keine konkrete Empfehlung geben. Wichtiger ist: Wie kontrollieren Sie die Größe des Bulks überhaupt?

Zeit

Arbeitsspeicherbedarf

Bulkgröße Abbildung 9.1 Abhängigkeit der Ausführungsgeschwindigkeit von der Bulkgröße

411

9.2

1452.book Seite 412 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

Die einfachste Variante ist natürlich, die lokale Kollektion immer nur mit entsprechend vielen Zeilen zu füllen und die Forall-Anweisung bei Bedarf aufzurufen. Dieses Codebeispiel liefert zudem endlich einmal eine sinnvolle Anwendung der MOD-Funktion: SQL> set timing on SQL> create or replace procedure SQL_performance_test_5 2 as 3 type value_table_type is table of pls_integer 4 index by binary_integer; 5 value_table value_table_type; 6 iterations integer := 10000; 7 idx integer := 0; 8 begin 9 for i in 1..iterations loop 10 idx := idx + 1; 11 value_table(idx) := i; 12 if mod(i, 100) = 0 or i = iterations then 13 forall indx in 1 .. 100 14 insert into test_table values(value_table(indx)); 15 value_table.delete(); 16 idx := 0; 17 end if; 18 end loop; 19 commit; 20 end; 21 / Prozedur wurde erstellt. SQL> call SQL_performance_test_5(); Aufruf wurde abgeschlossen. Abgelaufen: 00:00:00.14 Listing 9.12 Balancierung einer Bulk-Anweisung zwischen Performanz und Ressourcenverbrauch

Eine andere Möglichkeit besteht darin, die Forall-Anweisung so anzupassen, dass nur Teilmengen eingefügt werden. Dies kann dadurch erreicht werden, dass eben andere Begrenzungszahlen eingefügt werden. Doch hilft das nicht bei unserem Problem mit dem Arbeitsspeicher, denn auch in diesem Fall müsste die Kollektion ja komplett aufgebaut im Arbeitsspeicher vorhanden sein. Sie sehen, dass einiger Aufwand betrieben werden muss, um diese Performanzvorteile zu nutzen. Andererseits ist der Erfolg aber auch so spektakulär, dass sich der Aufwand lohnt.

412

1452.book Seite 413 Donnerstag, 5. August 2010 3:55 15

PL/SQL-Kollektionen

Fehlerbehandlung bei Bulk-Operationen Beim Schreiben im Bulk stellt sich zudem noch ein wesentliches Problem: Wie wird mit Fehlern umgegangen, die die Schreibprozesse ausführen? Hier stehen wieder einmal mehrere Möglichkeiten zur Verfügung. Bei der »normalen« Verwendung, wie im vorigen Abschnitt beschrieben, werden eventuelle DML-Fehler sofort ausgelöst und die gesamte Aktion rückgängig gemacht. Allerdings steht eine optionale Klausel zur Verfügung, die dieses Verhalten ändert und alle auftretenden Fehler bis zum Ende der Forall-Anweisung speichert, die erfolgreichen Aktivitäten jedoch belässt: forall indx in 1 .. 100 insert into test_table values(value_table(indx)) save exceptions;

Mit dieser zusätzlichen Klausel wird bei eventuell auftretenden Fehlern ein Attribut bulk_exceptions (für den Cursor SQL) gefüllt, das nach der Ausführung abgefragt werden kann. Am Ende der Arbeit wird dann nur noch ein einzelner Fehler (ora-24381) ausgelöst, der anzeigt, dass überhaupt Fehler während der Verarbeitung aufgetreten sind. Dieser Fehler muss im Code zunächst abgefangen werden, damit im Exception-Teil des Codes die Fehlerliste explizit geprüft werden kann: SQL> 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

create or replace procedure SQL_performance_test_5 as type value_table_type is table of pls_integer index by binary_integer; value_table value_table_type; iterations number := 10000; err_amount number; dml_errors exception; pragma exception_init(dml_errors, -24381); procedure print(text in varchar2) as begin dbms_output.put_line(text); end; begin for i in 1..iterations loop value_table(i) := i; end loop; forall indx in 1 .. iterations save exceptions insert into test_table values(value_table(indx)); commit; exception

413

9.2

1452.book Seite 414 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

24 when dml_errors then 25 err_amount := sql%bulk_exceptions.count; 26 print('Fehler während der Ausführung: ' || err_amount); 27 for I in 1 .. err_amount loop 28 print('.- Nr. ' || i || ', Iteration: ' || 29 sql%bulk_exceptions(i).error_index); 30 print('. Meldung: ' || 31 sqlerrm(-sql%bulk_exceptions(i).error_code)); 32 end loop; 33 end; 34 / Prozedur wurde erstellt.

Um bei der Ausführung dieser Prozedur nun Fehler provozieren zu können, nehmen wir folgende Veränderungen vor: Zum einen wird die Tabelle auf Zahlen bis 9999 begrenzt, zum anderen füge ich eine Zeile ein und verschärfe das Datenmodell durch einen Unique-Constraint: SQL> alter table test_table add constraint u_test_table unique(id); Tabelle wurde geändert. SQL> alter table test_table modify (id number(4,0)); Tabelle wurde geändert. SQL> insert into test_table values(123); 1 Zeile wurde erstellt. SQL> commit; Transaktion mit COMMIT abgeschlossen.

Nun sollte ein erneutes Ausführen der Prozedur einen Fehlerbericht ergeben: SQL> set serveroutput on SQL> call sql_performance_test_5(); Fehler während der Ausführung: 2 .- Nr. 1, Iteration: 123 . Meldung: ORA-00001: Unique Constraint (.) verletzt .- Nr. 2, Iteration: 10000 . Meldung: ORA-01438: Wert größer als die angegebene Gesamststellenzahl, die für diese Spalte zulässig ist Aufruf wurde abgeschlossen. Listing 9.13 Bulk-Anweisung mit Fehlerbehandlung

Bulk-Select Sehen wir uns noch eine weitere Anwendung an, die ebenfalls häufig verwendet wird: das Lesen im Bulk. Bei dieser Anwendung müssen viele Werte aus einer

414

1452.book Seite 415 Donnerstag, 5. August 2010 3:55 15

PL/SQL-Kollektionen

Tabelle in eine lokale Variable umkopiert werden. Es soll kein Cursor eingesetzt werden, denn die Daten sollen z.B. in einem Package persistiert werden. In diesem Fall bietet es sich an, die Leseoperation im Bulk durchzuführen, wie im folgenden Beispiel, in dem die Tabelle dept in eine lokale geschachtelte Tabelle umkopiert werden soll: SQL> declare 2 type dept_tab_t is table of dept%rowtype; 3 dept_tab dept_tab_t; 4 begin 5 select * 6 bulk collect into dept_tab 7 from dept 8 order by deptno; 9 end; 10 / PL/SQL-Prozedur erfolgreich abgeschlossen. Listing 9.14 Bulk-Select-Anweisung

Das liest sich gut: Hier ist es lediglich erforderlich, eine Kollektion im richtigen Typ zur Aufnahme der Daten anzubieten und anschließend die Select-Anweisung um die Klausel bulk collect into zu erweitern. Achten Sie aber auch hier auf den Speicherverbrauch: Dieses Verfahren ist nicht geeignet, um SQL »besser« zu machen. Die mit einer SQL-Anweisung verbundenen Datenmengen können wirklich erheblich sein. Diese Anweisung kopiert diese Daten in den Arbeitsspeicher, und zwar so lange, bis dieser dicke Backen macht. Zudem müssen Sie überlegen, ob Sie bei der Ausführung einer solchen Anweisung noch andere Benutzer auf der Datenbank haben, die vielleicht Ähnliches vorhaben. Konkret empfehle ich diese Anweisung, wenn Sie ohnehin eine lokale Kopie der Daten vorhalten müssen. Dann kommen Sie um den Speicherplatz nicht herum, und dann ist diese Art der Anweisung wahrscheinlich schneller als die »normale« Iteration über einen Cursor.

9.2.3

Tabellenfunktionen (PIPELINED-Functions)

Prozeduren oder Funktionen, die Daten, z.B. in einer Schleife, berechnen, tun dies im Normalfall komplett, bevor sie das Ergebnis zurückliefern. Dieses Verhalten hat den Vorteil, dass es einfach zu implementieren ist, und ist normalerweise auch ausreichend. In Datenbanken jedoch stehen wir oft vor dem Problem, sehr große Datenmengen bearbeiten zu müssen. Werden diese großen Datenmengen durch eine PL/SQL-Funktion geschleust, kann das zur Folge haben, dass die Anforderungen an den Arbeitsspeicher die Bearbeitung stark verlangsamen oder

415

9.2

1452.book Seite 416 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

eventuell sogar unmöglich machen können. Zudem gibt es häufig Situationen, in denen die Ergebnisse einer Prozedur durch andere Anweisungen weiterverarbeitet werden müssen. Es ist häufig möglich, bereits mit Teilergebnissen weiterzuarbeiten, die Funktion muss also nicht komplett bearbeitet werden, bevor der nächste Arbeitsschritt ausgeführt werden kann. In solchen Situationen wäre es sinnvoll, die Teilergebnisse bereits an einen anderen Prozessor weiterzureichen, während die Funktion noch andere Informationen bearbeitet. Für solche Funktionen können Funktionen so definiert werden, dass sie Teilergebnisse aus der laufenden Funktion heraus zurückliefern. Damit dies funktioniert, muss die Funktion einen Kollektionstyp zurückliefern und mit der Klausel pipelined definiert werden. Vielleicht ist es auch hier wieder das Einfachste, wenn ich Ihnen ein Beispiel zeige. Die XML-Datenbank (XDB) stellt Ihnen eine Möglichkeit zur Verfügung, Daten in einer Ordnerhierarchie innerhalb der Datenbank zu speichern. Letztlich wird dabei für jeden Ordner eine Zeile in einer Datenbanktabelle angelegt und mittels des Protokolls WebDAV so angezeigt, als sei dies ein Dateisystem. Sie können neue Ordner in dieser Tabelle anlegen, unterliegen dabei aber der Beschränkung, dass nur Unterordner in bestehenden Ordnern angelegt werden können. Möchten Sie also auf einen Rutsch ein Verzeichnis, z.B. /etc/examples/pl_sql/chap_2 anlegen, so müssen Sie zunächst sicherstellen, dass das Verzeichnis /etc, dann das Verzeichnis /etc/examples und so weiter existiert. Existieren diese Verzeichnisse nicht, so müssen sie nacheinander angelegt werden. Um nun also beliebige Ordner anlegen zu können, benötigen wir eine Funktion, die uns diese Ordner in der entsprechenden Reihenfolge anlegt. Zwar können wir uns eine Funktion vorstellen, die in einer Schleife die Einzelbestandteile der Pfade ausgibt. Doch ist die Funktion dann doch etwas unhandlich, denn wir benötigen ja eigentlich nicht die einzelnen Bestandteile, sondern eine Liste von Ausgaben dieser Form: /etc /etc/examples /etc/examples/pl_sql /etc/examples/pl_sql/chap_2

Außerdem möchten wir mit diesen Daten anschließend eine Insert-Anweisung ausstatten, die dann die einzelnen Verzeichnisse anlegt. Wie lösen wir ein solches Problem? Vielleicht sollten wir eine Schleife schreiben, die die einzelnen Werte der Insert-Anweisungen berechnet und diese dann im Schleifendurchlauf aufruft. Das ist sicher eine Möglichkeit, doch hätte dies zur Folge, dass wir mehrfach Insert-Anweisungen für einzelne Zeilen aufrufen. Schöner wäre, wir könnten eine Insert-Anweisung für alle Zeilen aufrufen. Eine bessere Variante wäre,

416

1452.book Seite 417 Donnerstag, 5. August 2010 3:55 15

PL/SQL-Kollektionen

diese Informationen im Bulk an die Datenbank zu senden, wie wir dies in Abschnitt 9.2.2, »Massenverarbeitung mit assoziativen Tabellen«, erläutert haben. Alternativ können wir dieses Verhalten aber auch mit einer Funktion erzeugen, die sich für die Insert-Anweisung wie eine Tabelle verhält und eine Anweisung der Form insert into zieltabelle select * from quelltabelle;

ermöglicht. Lassen Sie uns an diesem Beispiel einmal eine solche Funktion erstellen. Zunächst einmal benötigen wir einen Rückgabewert der Funktion, der in der Lage ist, eine Kollektion von Werten aufzunehmen. In unserem Beispiel wäre das also eine Tabelle von Zeichenketten. Wir erzeugen also zunächst diesen Rückgabetyp: SQL> create type varchar_tab as table of varchar2(2000 char); 2 / Typ wurde erstellt.

Anschließend können wir eine Funktion deklarieren, die diesen Datentyp zurückliefert und mit der Klausel pipelined zu einer Tabellenfunktion wird: SQL> create or replace function get_sub_pathes( 2 path in varchar2) 3 return varchar_tab pipelined 4 as 5 begin 6 return; 7 end get_sub_pathes; 8 / Funktion wurde erstellt. Listing 9.15 Grundgerüst einer Tabellenfunktion

Durch diese Deklaration ändern sich einige Dinge an der Art, die Funktion zu programmieren. Zunächst einmal enthält die Return-Klausel nun keinen Wert mehr, sondern steht allein, und zwar so, wie Sie das in Zeile 6 des Listings sehen können. An den Stellen (typischerweise natürlich innerhalb einer Schleife), an denen die Funktion Werte zurückliefern soll, wird nun das Schlüsselwort pipe row sowie der Rückgabewert in Klammern eingefügt. Durch diese Anweisung wird die Funktion die Werte an die aufrufende Umgebung zurückliefern. Der Datentyp, der zurückgeliefert wird, muss dabei dem Basistyp der Kollektion entsprechen. In unserem Fall ist dies also eine Zeichenkette bis 2000 Byte Länge.

417

9.2

1452.book Seite 418 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

Sehen wir nun also die Funktion an, die unsere Zeichenkette in Einzelteile zerschneidet und die Einzelteile an die aufrufende Umgebung zurückliefert: SQL> create or replace 2

function get_sub_pathes(path in varchar2)

3 4

return varchar_tab pipelined as

5

idx pls_integer := 1;

6

sub_path varchar2(2000);

7

begin

8

while idx > 0 loop

9

idx := instr(path, '/', idx + 1); -- ignore root slash

10

case idx

11

when 0 then sub_path := path;

12

else sub_path := substr(path, 1, idx - 1);

13

end case;

14

pipe row (sub_path);

15

end loop;

16

return;

17

end get_sub_pathes;

18

/

Funktion wurde erstellt. SQL> select column_value 2

from table( get_sub_pathes( '/etc/examples/pl_sql/chap_2'));

COLUMN_VALUE ----------------------------------------------------------------/etc /etc/examples /etc/examples/pl_sql /etc/examples/pl_sql/chap_2 Listing 9.16 Beispiel einer Tabellenfunktion

Wie Sie sehen, werden die Unterpfade als Zeichenkette während der Iterationen aus der Funktion heraus geliefert. Dies hat den Vorteil, dass der durch das Ergebnis allozierte Speicherbereich freigegeben und das Ergebnis durch die aufrufende Umgebung weiterbearbeitet werden kann. In unserem Fall sammeln wir die Ergebnisse und fügen sie in einem Rutsch im Rahmen einer Insert-Anweisung in eine Tabelle ein. Beachten Sie in unserem Beispiel bei der nachfolgenden Abfrage die Verwendung des Konstruktors table(), der das Ergebnis der Funktion in

418

1452.book Seite 419 Donnerstag, 5. August 2010 3:55 15

PL/SQL-Kollektionen

eine für SQL verwertbare Tabelle umformt. Bei dieser Umformung wird der Rückgabewert in einer Tabelle mit dem Spaltennamen column_value überführt, der dann durch SQL abgefragt werden kann. Die Funktion ist im Übrigen auch ein schönes Beispiel für die Verwendung einer While-Schleife, denn die Anzahl der Iterationen durch die Schleife ist nicht bekannt, sondern vom übergebenen Parameter abhängig, andererseits aber auch gut außerhalb der Schleife überprüfbar und daher besser als eine Exit-Klausel im Schleifenkörper. Eine andere, sehr witzige Anwendung einer solchen Prozedur stellt die Verwendung als Bindevariable für Listen dar. Das Problem: Sie sollten Bindevariablen benutzen, um eine SQL-Anweisung im Library-Cache der Datenbank wiederauffindbar zu halten und dadurch die Anzahl der Parse-Vorgänge niedrig zu halten. Gut. Aber wie machen Sie das bei einer Anweisung wie der folgenden? SQL> select * 2 3

from emp where job in ('MANAGER', 'ANALYST');

Wie sollen Sie nun die Liste der Berufe als Bindevariable übergeben? Wenn eine Variable die Liste der Werte enthält, suchen wir auch nach einem Beruf, der so heißt wie die Liste der Berufe, die übergeben wird. Das geht also nicht. Stattdessen benötigen wir einen Weg, der SQL-Anweisung klarzumachen, dass eine Liste von Werten durchsucht werden soll. Die »beweglichen Teile«, die wir benötigen, um das Problem zu lösen, haben wir eigentlich schon programmiert, denn unsere Tabellenfunktion von vorhin könnte nach einer kleinen Modifikation ja statt eines wachsenden Pfades gern auch die einzelnen Ordnernamen ausgeben. Dann könnten wir die Funktion im Kontext der obigen Abfrage wie eine Bindevariable für Listenwerte nutzen, und zwar gleich auf zwei Arten: select * from emp e, table(string_to_tab(csv_liste)) l where e.job = l.column_value;

oder: select * from emp where job in (select column_value from table( string_to_tab(csv_liste)));

Dabei bestehen gute Chancen, dass der Optimizer der Datenbank beide Varianten mit dem gleichen Ausführungsplan belegt. Im obigen Pseudocode ist der Parameter csv_liste eine Variable mit einer kommaseparierten Liste der einzel-

419

9.2

1452.book Seite 420 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

nen Berufe, die durch die (neu zu schreibende) Tabellenfunktion string_to_tab in eine virtuelle Tabelle mit den Berufen umgebaut wird. Die Implementierung dieser neuen Funktion (vielleicht möchten Sie die Funktion auch gleich für Zahlen und Datumsangaben programmieren?) überlasse ich Ihnen als Übung. Einen Hinweis hätte ich aber zu dieser Aufgabe noch: Das Umwandeln einer kommaseparierten Liste in eine assoziative Tabelle liefert Ihnen Oracle mit: Sehen Sie sich einmal die Prozedur dbms_utility.comma_to_table an. Dann bliebe nur noch die Ausgestaltung als Tabellenfunktion. Tabellenfunktionen werden laut Oracle-Dokumentation vor allem im Bereich von Datenwarenhäusern empfohlen, um die Verarbeitung von Daten in Queues zu optimieren. Die Idee: Große Datenmengen werden durch eine Funktion iterativ verarbeitet und an die nächste Verarbeitungsstufe weitergegeben. Dadurch sinkt die Speicherbelastung, und es steigt die Fähigkeit zur Parallelisierung der Aufgabe, weil andere Prozessoren die Teilergebnisse bereits verarbeiten können, während die Funktion noch an der vorhergehenden Stufe arbeitet. Das ist sicherlich richtig, doch möchte ich den Einsatzbereich dieser Funktionen gern erweitern und Ihnen dieses Konzept auch für andere Aufgaben ans Herz legen. Um Ihnen ein weiteres Einsatzfeld für solche Funktionen aufzuzeigen, programmieren wir uns einen Monatsgenerator, der in der Lage ist, eine beliebige Anzahl Monate ab einem Startmonat zu liefern. Beginnen wir also wieder mit einem Kollektionstyp für Datumsangaben: SQL> create type date_tab as table of date; 2 / Typ wurde erstellt.

Nun folgt die Funktion. Sie erwartet ein Startdatum und eine Anzahl von Monaten, die erzeugt werden sollen: SQL> create or replace function get_months ( 2 start_month in date, 3 month_amount in pls_integer) 4 return date_tab pipelined 5 as 6 begin 7 for i in 1 .. month_amount loop 8 pipe row (add_months(start_month, i)); 9 end loop; 10 return; 11 end get_months; 12 / Funktion wurde erstellt.

420

1452.book Seite 421 Donnerstag, 5. August 2010 3:55 15

PL/SQL-Kollektionen

SQL> select column_value monat 2 from table( get_months( to_date('01.01.1980', 'dd.mm.yyyy'), 23)); MONAT -------01.02.80 01.03.80 … 01.12.81 24 Zeilen ausgewählt. Listing 9.17 Verwendung einer Tabellenfunktion als virtuelle Tabelle

Beachten Sie wiederum die Verwendung der Pseudospalte column_value in der Select-Anweisung. Mithilfe dieser Funktion können Sie nun beliebig viele Monate abrufen, ohne diese in einer Tabelle vorhalten zu müssen. Fragen Sie sich, wozu eine solche Liste von Monaten gut sein soll? Nun, vielleicht benötigen Sie eine Auswertung der Anzahl der Einstellungen in Ihr Unternehmen, gruppiert nach Monat. Was geschieht nun, wenn in einem Monat keine Mitarbeiter eingestellt wurden? In diesem Fall würde kein Ergebnis für diesen Monat ausgegeben werden. Um dies aber zu erfahren, benötigen Sie eine Referenztabelle, die alle Auswertungsmonate enthält. Folgende, stark vereinfachte Auswertung könnten Sie also verwenden: SQL> select d.column_value monat, 2 count(trunc(hiredate, 'MM')) einstellungen 3 from emp e right join 4 table( 5 get_months( 6 to_date('01.01.1980', 'dd.mm.yyyy'), 23)) d 7 on trunc(e.hiredate, 'MM') = d.column_value 8 group by d.column_value; MONAT EINSTELLUNGEN -------- ------------01.04.80 0 01.09.80 0 01.10.80 0 01.10.81 0 01.12.81 2 … 01.04.81 1 23 Zeilen ausgewählt. Listing 9.18 Einsatz einer Tabellenfunktion

421

9.2

1452.book Seite 422 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

Tabellenfunktionen verhalten sich also in gewisser Weise wie normale Datenbanktabellen, die in SQL-Abfragen verwendet werden können. Und sie haben es sich wahrscheinlich schon gedacht: Daher rührt auch der Name. Weil aber Tabellenfunktionen darüber hinaus auch Kollektionen oder Cursor als Eingabeparameter akzeptieren, können sie in einem Workflow eingesetzt werden, in dem die Ergebnisse z.B. einer SQL-Abfrage iterativ an die Tabellenfunktion und von dort an eine weitere SQL-Anweisung weitergeben wird, und das ohne übermäßige Speicherbelastung, denn die kompletten Ergebnisse der Prozedur werden niemals materialisiert, sondern lediglich die einzelnen Teilergebnisse. Das folgende Beispiel zeigt, wie die Ergebnisse einer Tabellenfunktion in eine weitere Tabellenfunktion gelangen und von dort in eine SQL-Anweisung geleitet werden. Allerdings liegen diese doch recht speziellen Einsatzgebiete etwas außerhalb des Fokus dieses Buches, daher dient das folgende Beispiel eher der Demonstration solcher Konstrukte: select * from table(f(cursor(select * from table(g()))));

Beachten Sie, wie durch den Konstruktor cursor() aus einer SQL-Ergebnismenge eine Cursor-Instanz generiert wird, die wiederum als Eingabeparameter der Tabellenfunktion f genutzt werden kann. Zum Schluss noch einen etwas obskur wirkenden Hinweis im Zusammenhang mit Tabellenfunktionen: Es gibt einen Fehler, der, so er denn auftritt, zwar geworfen wird, das Programm aber nicht zum Abbruch zwingt. Dieser Fehler hat den Namen no_data_needed und wird immer dann geworfen, wenn ein, in einer Tabellenfunktion geöffneter, Cursor nicht komplett gelesen wird. Es führt wahrscheinlich ein wenig zu weit, die Interna dieses Fehlers genauer zu beleuchten. Ich möchte lediglich aus dieser Tatsache den Tipp für Sie ableiten, zum Ende einer Tabellenfunktion stets folgenden Exception-Handler zu schreiben: exception when no_data_needed return; Listing 9.19 Fehlerhandler in Tabellenfunktionen

Sie stellen mit diesem Fehlerhandler sicher, dass keine Speicherressourcen offengelassen werden und der Cursor der Tabellenfunktion unter allen Umständen sauber geschlossen wird.

422

1452.book Seite 423 Donnerstag, 5. August 2010 3:55 15

Mengenverarbeitung mit Cursorn

9.3

Mengenverarbeitung mit Cursorn

Die grundlegenden, syntaktischen Details zur Arbeit mit Cursoren haben wir uns ja bereits in Abschnitt 7.4, »Kollektionen in PL/SQL«, angesehen. In diesem Abschnitt sollen nun Anwendungsbeispiele und weitergehende Konzepte folgen. Wir werden uns ansehen, auf welche Weise die zum Teil ja immens großen Datenmengen, die durch einen Cursor repräsentiert werden können, am besten verwaltet werden.

9.3.1

Implizite versus explizite Cursor

Diskussionen unter PL/SQL-Fachleuten drehen sich zuweilen um die Frage, ob ein Cursor implizit oder immer explizit definiert und genutzt werden sollte. Aus meiner Sicht handelt es sich bei der Diskussion eigentlich um zwei Diskussionen, denn einerseits bezieht sie sich darauf, ob stets ein Cursor definiert und abgefragt werden solle oder eine SQL-Abfrage direkt in PL/SQL eingebunden werden sollte, andererseits darauf, ob die verkürzte Schreibweise einer Cursor-ForSchleife der expliziten Kontrolle eines Cursors mit open, fetch und close bevorzugt werden sollte. Sehen wir uns beide Bereiche an: Ich nenne die erste Diskussion die Frage nach impliziten oder expliziten Cursorn, die zweite die Diskussion um implizite oder explizite Cursorkontrolle. Implizite oder explizite Cursor Um eine Tabellenzelle aus der Datenbank in eine PL/SQL-Variable umzukopieren, stehen im Grunde zwei Möglichkeiten zur Wahl. Einerseits können wir einen Cursor definieren, diesen explizit öffnen, eine Zeile herausholen und den Cursor anschließend schließen. Dies wäre ein expliziter Cursor, denn wir haben den Cursor unter voller Kontrolle. Die Alternative wäre eine einfache Select-IntoAnweisung, die das Ergebnis direkt in eine PL/SQL-Variable kopiert. Welcher Weg ist besser? Gerade in früheren Zeiten wurde der expliziten Methode deutlich der Vorzug gegeben. Der Grund: Bei der Verwendung eines impliziten Cursors kann die Fehlermeldung too_many_rows auftauchen, wenn die Abfrage mehr als nur eine Zeile zurückliefert. Um diese Fehlermeldung zu erzeugen – so wurde argumentiert –, muss die Datenbank mindestens zwei Fetch-Operationen auf den impliziten Cursor durchführen, um die weitere Zeile zu lesen. Dieses Problem existiert beim expliziten Cursor nicht, denn dort wird ja explizit gelesen. Zum Glück ist dieses Argument schon seit sehr langer Zeit nicht mehr stichhaltig: Bereits Version 7.1 führte den Pre-Fetch-Mechanismus beim Lesen von Cursorn ein, eine Art Caching, wie es auch beim Lesen von Festplatten etc. durchgeführt wird. Dieser

423

9.3

1452.book Seite 424 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

Mechanismus liest ohnehin mehrere Zeilen in einem Durchgang vom Cursor und kann so auch den oben beschriebenen Fehler direkt aufdecken. Doch gibt es auch ohne dieses Argument noch einige Pros und Contras, die wir uns im Folgenden etwas näher ansehen sollten. Sehen wir uns die beiden Implementierungen im Vergleich einmal an: SQL> declare 2 emp_id emp.empno%type; 3 begin 4 select empno 5 into emp_id 6 from emp 7 where ename = 'KING'; 8 exception 9 when no_data_found then raise; 10 when too_many_rows then raise; 11 end; 12 / PL/SQL-Prozedur erfolgreich abgeschlossen.

Und nun das Ganze explizit: SQL> declare 2 cursor emp_cur (name in varchar2) is 3 select empno 4 from emp 5 where ename = name; 6 emp_id emp_cur%rowtype; 7 begin 8 open emp_cur('KING'); 9 fetch emp_cur into emp_id; 10 close emp_cur; 11 end; 12 / PL/SQL-Prozedur erfolgreich abgeschlossen. Listing 9.20 Vergleich impliziter versus expliziter Cursor

Der Nachteil der impliziten Variante ist sicher die Verpflichtung, auftretende Fehler abfangen zu müssen. Insbesondere sind es zwei Fehler, die auftreten können: Es wird keine Zeile gefunden, oder es werden mehrere Zeilen gefunden. Diese Fehler müssen durch einen Exception-Block aufgefangen werden. Zwar ließe sich die Abfrage gegen den Fehler too_many_rows dadurch schützen, dass zur Where-Klausel noch der Ausdruck and rownum = 1 hinzugefügt wird, um meh-

424

1452.book Seite 425 Donnerstag, 5. August 2010 3:55 15

Mengenverarbeitung mit Cursorn

rere Zeilen zu unterdrücken; ein solcher Ausweg existiert jedoch für den Fehler no_data_found nicht. Sie mögen sagen, es handele sich ja nun auch um Fehler, daher ist es richtig, diese im Fehlerbehandlungsteil zu behandeln, doch teile ich diese Auffassung nur bedingt: Mir scheinen diese »Fehler« eher zu erwartende Ausnahmen zu sein, denn wenn ich z.B. einen Suchbegriff über eine Oberfläche einfüge, kann es nun mal sein, dass ich zu diesem Begriff kein Ergebnis finde. Daher könnte mich dieser Fakt dazu zwingen, den impliziten Cursor in einen Begin-Exception-Block zu stecken, um die Ausführung der gesamten Prozedur nicht zu gefährden. Dies ist sicher ein Nachteil gegenüber dem expliziten Cursor, denn ein Fetch auf einen leeren (aber geöffneten!) Cursor hat keine Fehlermeldung zur Folge, ebenso wenig wie das Öffnen eines Cursors mit leerer Ergebnismenge. Oft wird einem expliziten Cursor auch der Vorzug gegeben, weil er offensichtlich effizienter eine Frage zu beantworten scheint als ein impliziter Cursor. Sehen wir uns stellvertretend einmal eine Existenzprüfung an. Bei diesem Problem soll geprüft werden, ob in Abteilung 20 überhaupt Mitarbeiter arbeiten oder nicht. Ein erster Ansatz könnte also auf eine SQL-Anfrage herauslaufen wie etwa diese: SQL> select count(*) anzahl 2 from emp 3 where deptno = 20; ANZAHL ---------5

Doch wollen wir eigentlich gar nicht wissen, wie viele Mitarbeiter in der Abteilung arbeiten, sondern es reicht uns, zu wissen, dass mindestens ein Mitarbeiter dort arbeitet. Gerade bei großen Tabellen ist der Aufwand für die komplette Zählung also unnötig teuer. Daher könnte uns folgender Code helfen: SQL> declare 2 cursor emp_dept is 3 select 1 found 4 from emp 5 where deptno = 20; 6 emp_found emp_dept%rowtype; 7 begin 8 open emp_dept; 9 fetch emp_dept into emp_found; 10 close emp_dept; 11 if emp_found.found = 1 then 12 dbms_output.put_line('Mitarbeiter gefunden'); 13 end if;

425

9.3

1452.book Seite 426 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

14 end; 15 / Mitarbeiter gefunden PL/SQL-Prozedur erfolgreich abgeschlossen.

Doch liegt hier der Fehler im SQL: Es ist einfach nicht der richtige Weg, eine Prüfung auf Existenz über die Anweisung count(*) durchzuführen, dafür gibt es das Konstrukt SQL> select 1 found 2 from dual 3 where exists(select 1 4 from emp 5 where deptno = 20); FOUND ---------1

und mithin die Möglichkeit, diese Abfrage implizit zu formulieren und direkt in eine lokale Variable umzukopieren. Zusammenfassend kann man es vielleicht so formulieren: Es ist nichts Falsches daran, einen Cursor explizit zu formulieren und zu benutzen. Dagegen spricht im Einzelfall wahrscheinlich die höhere Codemenge, die benötigt wird, um ihn zu deklarieren. Für explizite Cursor spricht die Fehlertoleranz. Es ist aber auch am Gegenteil nichts falsch, und wenn dadurch die Menge des Codes reduziert wird, plädiere ich für die lesbarere Variante. Im Übrigen ist es immer richtig, sich zunächst einmal darüber zu informieren, ob eine gewisse Aussage nicht auch in SQL formuliert werden kann, denn dieser Weg ist eigentlich immer der beste. Implizite oder explizite Cursorkontrolle Cursor können, wie bereits besprochen, explizit über eine eigene Deklaration und die Behandlung über open, fetch und close gesteuert, oder aber im Rahmen von Cursor-For-Schleifen implizit verwaltet werden. Dabei stellt sich die Frage, ob der eine Weg dem anderen vorzuziehen ist und welche Überlegungen angestellt werden sollten, um die Wahl zwischen den beiden Varianten zu treffen. Zunächst einmal gibt es Fälle, in denen die Wahl nur durch einen expliziten Cursor erfüllt werden kann. Dies ist zum Beispiel dann der Fall, wenn der Cursor nicht in einem Rutsch, sondern in mehreren, unabhängigen Teilschritten bearbeitet werden soll. Stellen wir uns dazu eine Funktion vor, die einen Cursor öffnet, die ersten 10 Zeilen des Cursors bearbeitet, anschließend eine andere Aufgabe ausführt und dann weitere 10 Zeilen des Cursors abarbeitet. In diesem Fall ist die Wahl relativ eindeutig, denn der Cursor einer Cursor-For-Schleife wird

426

1452.book Seite 427 Donnerstag, 5. August 2010 3:55 15

Mengenverarbeitung mit Cursorn

beim Verlassen der Schleife implizit geschlossen und die Ergebnismenge verworfen. Zudem ist es schwierig oder zumindest unnötig aufwendig, eine Position im Cursor gezielt »anzufahren«, um zum Beispiel dort fortzufahren, wo ein früheres Öffnen und teilweises Bearbeiten des gleichen Cursors geendet hat. Denken Sie nur daran, dass zwei gleiche Abfragen nacheinander nicht das gleiche Ergebnis liefern müssen, um das Problem zu verstehen. Und selbst wenn die Abfragen das gleiche Ergebnis liefern, ist nicht garantiert, dass die Daten in der gleichen Reihenfolge geliefert werden, falls Sie keine explizite Sortierreihenfolge über eine Order-By-Klausel vorgegeben haben. Ein explizit verwalteter Cursor ist demgegenüber einfach zu handhaben, denn die einmal erkannte Ergebnismenge bleibt konstant, bis der Cursor geschlossen wird. Ich kann nun also ohne Schwierigkeiten einen Cursor öffnen, eine Teilmenge verarbeiten, eine andere Arbeit ausführen und anschließend mit der Bearbeitung des Cursors fortfahren. Solche Fälle sind gar nicht so selten, wie dies auf den ersten Blick erscheinen mag: Stellen wir uns vor, eine Ergebnismenge bestehe aus 250 Zeilen, die durch einen Cursor auf der Datenbank erkannt wurden. Davon werden 50 Zeilen an die Oberfläche gesendet, und erst dann, wenn der Benutzer weitere Daten sehen möchte, fordert er weitere Daten an. Dieser Fall könnte mit einem expliziten Cursor leicht umgesetzt werden. Ebenso wäre es in diesem Fall falsch, die Anfrage bei Neuanforderung erneut auszuführen: Die große Zeitspanne, die zwischen der ersten und der zweiten Anfrage verginge, beinhaltete eine zu große Gefahr, unterschiedliche Daten zu liefern. Ebenso verhält es sich, wenn der Cursor als Cursorvariable von mehreren Funktionen bearbeitet werden soll. Auch hier ist die explizite Verarbeitung günstiger. Ganz besonders gilt das natürlich für Cursorvariablen, die über Systemgrenzen hinweg genutzt werden sollen. Diesen speziellen Fall werden wir im nächsten Abschnitt gesondert betrachten. Keine Entscheidungshilfe kommt im Übrigen aus Überlegungen zur Performanz des einen oder anderen Cursortyps: Beide Cursor sind im Großen und Ganzen gleich schnell. Das hat seinen Grund darin, dass Oracle im Laufe der Jahre große Anstrengungen unternommen hat, die Arbeit mit Cursorn einfach und intuitiv zu gestalten. Daher sollte aus meiner Sicht folgende Empfehlung gelten: Verwenden Sie implizit verwaltete Cursor, solange kein wichtiger Grund gegen diese Typen spricht. Implizite Cursor sind leichter zu schreiben und zu verstehen, genauso schnell, und die Gefahr, einen Cursor unbeabsichtigt geöffnet zu lassen und dadurch Speicherlecks zu riskieren, besteht nicht. Wo wir allerdings gerade dabei sind: PL/SQL kennt derzeit noch keinen Befehl, der dem Finally-Block in Java entspräche, also einem Block, der in jedem Fall,

427

9.3

1452.book Seite 428 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

auch bei Auftreten eines Fehlers, ausgeführt wird. Daher liegt es bei der Verwendung expliziter Cursor in Ihrer Verantwortung, Cursor im Fehlerfall zu schließen. Hierzu bietet sich natürlich zum Beispiel der Exception-Block an. Achten Sie aber darauf, dass alle abgefangenen Fehler auch die offenen Cursor schließen. Allerdings: Cursor, die innerhalb einer Funktion oder Prozedur definiert wurden, werden, wie alle anderen lokalen Variablen auch, nach Verlassen der Prozedur auch wieder gelöscht. Daher bezieht sich der Hinweis auf Cursor, die z.B. auf Package-Ebene definiert wurden und ihre Ergebnismenge für die gesamte Datenbanksession behalten. Ein eher ästhetisches Argument sei noch einmal wiederholt: Da die Deklaration eines Cursors irgendwann auf einer SQL-Anweisung beruht, muss diese Anweisung irgendwo hinterlegt werden. Dabei bieten sich mehrere Möglichkeiten an: 왘 in einer Cursor-For-Schleife Dieser Weg ist aus meiner Sicht nur für sehr kurze SQL-Anweisung anwendbar, längere SQL-Anweisungen stören das Verständnis der Schleife doch sehr. 왘 in einer Cursordeklaration im Deklarationsabschnitt der Prozedur Dieser Ansatz erscheint mir für kurze bis mittlere SQL-Anweisungen dann in Ordnung, wenn insgesamt relativ wenige Cursor in der Anwendung verwendet werden oder die Cursor nur von internem Interesse für die Funktion oder Prozedur sind. 왘 in einem Package Bei diesem Ansatz werden die Cursor in einem Package gesammelt und dort im Package-Körper deklariert. Dieses Verfahren bietet sich als zentrale Sammelstelle für SQL-Anweisungen für einen Funktionsbereich an, wenn diese Anweisungen nicht nur interne Bedeutung haben. 왘 als Views in der Datenbank Dies ist sicher der komfortabelste Weg, denn in diesem Umfeld können Sie die Anweisungen jederzeit testen, ohne die beteiligten Funktionen oder Prozeduren aufrufen zu müssen. Zudem sind Views gut zu warten und zu dokumentieren. Dieser Ansatz hat seine Schwächen, wenn das Datenbankschema relativ offen für andere Benutzer ist, da durch die Views eventuell Implementierungsdetails offengelegt werden könnten, die in Packages besser zu verbergen sind. Allerdings sind SQL-Anweisungen fast nicht zu verbergen: Spätestens beim Tracen der Session werden alle SQL-Anweisungen sichtbar, sodass dieses Argument möglicherweise nicht stichhaltig ist. Für welche Variante Sie sich auch entscheiden, wichtig ist, dass Sie eine bewusste Entscheidung fällen. Je umfangreicher das Projekt ist, umso bedeutender werden

428

1452.book Seite 429 Donnerstag, 5. August 2010 3:55 15

Mengenverarbeitung mit Cursorn

diese Entscheidungen. Zur Cursor-For-Schleife noch eine Anmerkung: Diese Schleifen können ja in den beiden Formen for rec in cur loop … end loop;

oder for rec in (SQL-Anweisung) loop … end loop;

geschrieben werden. Gerade bei der zweiten Schreibweise steht uns allerdings kein Cursorattribut zur Verfügung, denn nach dem Verlassen der Schleife gibt es keinen Cursor mehr. Daher müssen Sie auf alternative Wege achten, wie Sie z.B. die Anzahl der verarbeiteten Zeilen ausgeben möchten. Hier bietet sich z.B. eine count-Variable an oder die Inklusion der Pseudospalte rownum in die SQL-Abfrage (Achtung, wenn Sie die Ergebnismenge sortieren möchten!).

9.3.2

Top-N-Analyse

Auch wieder mal eines dieser Buzzwords! Unter einer Top-N-Analyse versteht man schlicht die Abfrage der besten n-Zeilen gemäß einem Sortierkriterium: die Top-5-Verdiener, die drei besten Produkte, die fünf schönsten Mädchen. Bei der Abfrage solcher Rangfolgen ist es natürlich zunächst einmal erforderlich, die Ergebnismenge zu sortieren. Dann aber scheiden sich die Geister: Wie soll die Abfrage durchgeführt werden? Zur Wahl stehen mindestens die folgenden beiden Wege: SQL> set serveroutput on; SQL> declare 2

cursor top_earner is

3

select empno, ename, sal

4

from emp

5

order by sal desc;

6 7

employee top_earner%rowtype; begin

8

open top_earner;

9

for i in 1 .. 5 loop

10

fetch top_earner into employee;

11

dbms_output.put_line(

12

'Rang ' || i || ': ' || employee.ename);

13

end loop;

14

end;

15

/

Rang 1: KING Rang 2: FORD

429

9.3

1452.book Seite 430 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

Rang 3: SCOTT Rang 4: JONES Rang 5: BLAKE PL/SQL-Prozedur erfolgreich abgeschlossen. Listing 9.21 Für Ihr Buzzwords-Vokabular: Eine Top-N-Analyse

Oder aber folgende Variante, die sich eigentlich nur im SQL unterscheidet: SQL> declare 2 cursor top_earner is 3 select * 4 from (select empno, ename, sal 5 from emp 6 order by sal desc) 7 where rownum < 6; 8 employee top_earner%rowtype; 9 begin 10 open top_earner; 11 fetch top_earner into employee; 12 while top_earner%found loop 13 dbms_output.put_line( 14 'Rang ' || top_earner%rowcount || 15 ': ' || employee.ename); 16 fetch top_earner into employee; 17 end loop; 18 end; 19 / Rang 1: KING Rang 2: SCOTT Rang 3: FORD Rang 4: JONES Rang 5: BLAKE PL/SQL-Prozedur erfolgreich abgeschlossen. Listing 9.22 Top-N-Analyse, Alternative 2

Lassen Sie sich ein wenig Zeit, um sich den Unterschied zwischen beiden Implementierungen klarzumachen. Die Frage reduziert sich letztlich auf folgende: Welche SQL-Anfrage ist besser? Auf den ersten Blick scheint klar zu sein, dass der Unterschied nur marginal ausfallen wird, denn schließlich müssen beide Anweisungen die gesamte Tabelle emp durchsuchen und die besten Verdiener finden. Im Zweifel ist die erste Verwendung zumindest kürzer, und da das SQL einfacher erscheint, sollte diese Variante das Mittel der Wahl sein. Doch ist genau das

430

1452.book Seite 431 Donnerstag, 5. August 2010 3:55 15

Mengenverarbeitung mit Cursorn

Gegenteil der Fall: Die zweite Implementierung ist, zumal bei sehr vielen Zeilen in emp, drastisch schneller! Woran liegt das? Oracle kann im zweiten Fall einen besonderen Algorithmus verwenden, der im ersten Fall nicht offensichtlich ist: Da die Datenbank weiß, dass Sie sich nur für die besten n Verdiener interessieren, kann sie eine Optimierung anwenden, die im Ausführungsplan als Order by Stopkey bezeichnet wird. Bei diesem Verfahren wird die Datenbank die zufällig ersten fünf Zeilen der Tabelle lesen und sortieren. Es wird in dieser Gruppe einen Mitarbeiter geben, der am wenigsten verdient, sagen wir, 1250 Taler. Dieses Gehalt wird nun mit dem Gehalt des 6. Mitarbeiters der Tabelle verglichen. Ist es höher, wird die 6. Zeile ignoriert und die nächste Zeile verglichen. Lediglich dann, wenn ein Mitarbeiter mehr als diese 1250 Taler verdient, muss er in die Riege der besten 5 Mitarbeiter aufgenommen werden, ansonsten kann der Datensatz ignoriert werden. Anschließend kann die Suche mit dem nun fünftbesten verdienenden Mitarbeiter fortgesetzt werden. Beim ersten Ansatz wird die Datenbank im Gegensatz hierzu gezwungen, die gesamte Tabelle zu sortieren, obwohl nachher lediglich die ersten 5 Zeilen dieser sortierten Menge abgefragt werden. Daher muss die gesamte Tabelle auch im UGA der Session gehalten werden (dort liegen die Sortierbereiche einer Session) und nicht nur die fünf Zeilen, auf die es ankommt. Und dies noch abgesehen von dem eingesparten Aufwand, auch noch den 317.-besten Verdiener sortieren zu müssen. Man hätte eigentlich drauf kommen können, nicht? Andererseits ist das eines der vielen Beispiele dafür, dass Sie der Datenbank sagen sollten, was Sie von ihr wollen, damit die Datenbank auch etwas für Sie tun kann. Gerade gestandene Anwendungsentwickler tendieren meiner Beobachtung zufolge dazu, der Datenbank »helfen« zu wollen, den richtigen Weg zu finden. Ich habe häufig die ernüchternde Erfahrung machen dürfen, dass die Datenbank meistens besser weiß, was für sie gut ist, als ich. Daher tendiere ich dazu, der Datenbank die Entscheidung zu überlassen, solange ich keinen starken, nachweisbaren Grund habe, dies nicht zu tun. Und natürlich ist das wieder einmal ein Argument für die Empfehlung, sich mit dem SQL der Datenbank auseinanderzusetzen, gegen die man programmiert. Als Anmerkung zu dieser Abfrage: Vielleicht noch etwas schneller geht die Suche mit einer Abfrage über eine analytische Funktion. Hier können wir uns die Abfrage z.B. so vorstellen: select * from (select empno, ename, sal, rank() over (order by sal desc) rang from emp) where rang < 6; Listing 9.23 Top-N-Analyse, Alternative 3

431

9.3

1452.book Seite 432 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

Diese analytische Funktion ist noch einmal gegenüber der besseren Abfrage von vorhin optimiert und daher eventuell (bitte testen!) noch einmal schneller. Wichtig ist mir aber: Sagen Sie der Datenbank, was Sie von ihr wollen, dann kann die Datenbank auch etwas für Sie tun.

9.3.3

Cursorvariablen (REF-Cursor)

Eine Cursorvariable ist eine Variable, die auf einen Cursor zeigt. Dieser Variablentyp wird verwendet, um auf eine Ergebnismenge zu zeigen, ohne diese tatsächlich zu beinhalten. Durch die Trennung von Cursorvariable und Cursor ergeben sich viele neue Möglichkeiten, die für die Programmierung von grundlegendem Interesse sind: 왘 Zunächst erhalten Sie mit einer Cursorvariablen die Möglichkeit, Cursor als Parameter an Prozeduren zu übergeben oder von dort als Ausgabeparameter oder Funktionsrückgabetyp zu erhalten. 왘 Dann können Cursorvariablen auf beliebige Cursor zeigen. Dadurch ergibt sich die Möglichkeit, beliebige Abfrageergebnisse durch eine einzige Methode verarbeiten zu lassen. 왘 Mehrere Variablen können auf denselben Cursor zeigen, unabhängig davon, wo sie deklariert sind. Auf diese Weise können z.B. Clientanwendungen auf Cursor zeigen, die auf dem Server liegen. Diese Cursor müssen also nicht komplett zum Client übertragen werden, sondern es werden lediglich dann Daten zum Client übertragen, wenn sie angefordert werden. Cursorvariablen werden als Typ definiert und anschließend genutzt, indem eine Variable dieses Typs deklariert wird. Das folgende Beispiel definiert eine sogenannte schwache Cursorvariable mit dem Namen my_cur. Schwach ist diese Cursorvariable in Hinblick auf ihre Typsicherheit, weil die Struktur der Ergebnismenge nicht bekannt ist. Diese Variable kann allerdings beliebige Cursor repräsentieren und ist damit sehr flexibel einsetzbar. Doch kann PL/SQL natürlich erst zur Laufzeit prüfen, ob die folgenden Zuweisungen auf Variablen etc. überhaupt gültig sind. Hier also der Code für diese Cursorvariable: declare type my_cur_t is ref cursor; my_cur my_cur_t; …

Sie kennen die grundsätzliche Vorgehensweise bereits aus der Arbeit mit Records oder assoziativen Tabellen. Im Gegensatz zu diesem schwachen Cursor steht die starke Cursorvariable, bei der zum Zeitpunkt der Deklaration bereits die Struktur des Cursors festgelegt

432

1452.book Seite 433 Donnerstag, 5. August 2010 3:55 15

Mengenverarbeitung mit Cursorn

wird. Zwar kann diese Cursorvariable immer noch beliebige Cursor repräsentieren, doch haben diese Cursor alle die gleiche vordefinierte Struktur. Auf diese Weise kann bereits zur Erstellungszeit geprüft werden, ob die nachfolgenden Manipulationen mit diesem Cursor machbar sind oder nicht. Sehen wir uns auch hierzu ein Beispiel an: declare type my_strong_cur_t is ref cursor return emp%rowtype; my_strong_cur my_strong_cur_t; …

Beiden Cursorvariablentypen ist gemeinsam, dass die Arbeit mit Ihnen weitgehend der mit einem »normalen« Cursor entspricht. Es stehen die gleichen CursorAttribute zur Verfügung: Auch hier wird über ein fetch eine Zeile geliefert und über die Anweisung close der (durch die Cursorvariable repräsentierte) Cursor geschlossen. Allerdings muss die Open-Anweisung für Cursorvariablen geändert werden, denn es muss ja irgendwann definiert werden, wie der Cursor, der durch diese Variable repräsentiert wird, definiert sein soll. Dies geschieht, indem die Open-Anweisung durch die For-Klausel erweitert und mit einer SQL-Abfrage spezifiziert wird. Sehen wir uns hierzu ein Beispiel an: SQL> declare 2 type my_strong_cur_t is ref cursor return emp%rowtype; 3 my_strong_cur my_strong_cur_t; 4 my_rec my_strong_cur%ROWTYPE; 5 begin 6 open my_strong_cur for 7 select * 8 from emp 9 where deptno = 10; 10 loop 11 fetch my_strong_cur into my_rec; 12 exit when my_strong_cur%NOTFOUND; 13 dbms_output.put_line(my_rec.ename || 14 ' arbeitet als ' || my_rec.job); 15 end loop; 16 close my_strong_cur; 17 end; 18 / CLARK arbeitet als MANAGER KING arbeitet als PRESIDENT MILLER arbeitet als CLERK PL/SQL-Prozedur erfolgreich abgeschlossen. Listing 9.24 Verwendung einer stark typisierten Cursor-Variablen

433

9.3

1452.book Seite 434 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

Achten Sie bitte darauf, dass Sie, wenn Sie eine schwache Cursorvariable verwenden, selbst dafür verantwortlich sind, keine Laufzeitfehler durch unmögliche Zuweisungen im Code zu erhalten. PL/SQL löst bei einer solchen unmöglichen Zuweisung die Fehlermeldung ROWTYPE_MISMATCH aus. Wir können, wie bereits angesprochen, eine Cursorvariable als Parameter einer Methode oder auch als Rückgabetyp einer Funktion deklarieren. Allerdings stellt sich dabei ein Problem: Wir haben ja gesehen, dass eine Cursorvariable als Typ deklariert und anschließend von diesem Typ abgeleitet werden muss. Dies stellt sich für eine Methode als sehr schwierig heraus, denn dort muss ein Parametertyp explizit angegeben werden. Folgender Versuch schlägt also fehl: SQL> create or replace procedure my_cursor_proc 2

(cur_in in ref cursor)

3

as

4

begin

5

null;

6

end;

7

/

Warnung: Prozedur wurde mit Kompilierungsfehlern erstellt. SQL> show errors Fehler bei PROCEDURE MY_CURSOR_PROC: LINE/COL ERROR -------- ----------------------------------------------------0/0

PL/SQL: Compilation unit analysis terminated

2/18

PLS-00201: Bezeichner 'CURSOR' muss deklariert werden

Listing 9.25 Versuch, eine Cursorvariable als Parameter zu übergeben

Andererseits können wir die Typdeklaration und die Ableitung einer Variablen in einer Parameterdeklaration nicht unterbringen. Welche Auswege bieten sich an? Zunächst einmal ist es zwar grundsätzlich möglich, Typen in SQL zu definieren, doch auch dieser Weg schlägt bei einer Cursorvariablen fehl, denn eine Cursorvariable kennt SQL nicht: SQL> create type refcur is ref cursor; 2

/

create type refcur is ref cursor; * FEHLER in Zeile 1: ORA-21561: OID-Generierung nicht erfolgreich

434

1452.book Seite 435 Donnerstag, 5. August 2010 3:55 15

Mengenverarbeitung mit Cursorn

Oracle versucht, einen SQL-Objekttyp zu erzeugen, und das gelingt nicht. Ein Ausweg ist die Verwendung eines Packages. Dies ist einer der vielen Vorteile von Packages. In einer Package-Spezifikation können wir einen Typ in PL/SQL verwenden und diesen anschließend im Prozeduraufruf verwenden. In der PackageSpezifikation können sowohl schwache als auch starke Cursorvariablen deklariert werden. Analog gehen Sie vor, wenn Sie eine Funktion deklarieren, die einen Cursor als Rückgabewert definiert: SQL> create or replace package cursor_pkg 2

as

3

type refcur is ref cursor;

4

procedure my_cursor_proc (cur_in in refcur);

5

function my_cursor_func (sql_stmt in varchar2)

6

return refcur;

7

end cursor_pkg;

8

/

Package wurde erstellt. Listing 9.26 Erste Variante: Implementierung als Package-Cursor

Ein anderer Weg ist die Verwendung eines vordefinierten Cursortyps in SQL: des sys_refcursor. Dieser Cursor kann allerdings nur als schwacher Cursortyp verwendet werden, wie im folgenden Beispiel gezeigt: SQL> create or replace procedure my_cursor_proc( 2

cur in sys_refcursor)

3

as

4

begin

5

null;

6

end my_cursor_proc;

7

/

Prozedur wurde erstellt. SQL> show errors Keine Fehler. Listing 9.27 Zweite Variante: Verwendung von »sys_refcursor«

9.3.4

Cursor-Ausdrücke

Eine weitere Variante der Verwendung von Cursorn sind die Cursor-Ausdrücke. Stellen wir uns hierzu vor, Sie müssten für eine Auswertung eine hierarchische Liste erstellen, in der die Mitarbeiter pro Abteilung aufgeführt werden sollen.

435

9.3

1452.book Seite 436 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

Der Bericht soll in PL/SQL erstellt werden. Nun könnten Sie die Aufgabe durch zwei Cursorn lösen: einen für jede Abteilung und einen für die Mitarbeiter der Abteilung. Sie haben aber auch die Möglichkeit, einen einzigen Cursor mit einem eingeschachtelten Cursor zu verwenden. Dazu können Sie in SQL eine harmonisierte Unterabfrage als Cursor deklarieren und die dadurch erzeugte Ergebnismenge durch geschachtelte Loop-Anweisungen durchlaufen. Wir sparen uns dadurch mehrere Roundtrips zum Server und verwalten die verschiedenen Cursor und deren Beziehungen untereinander implizit in einer Struktur. Die Benutzung solcher Cursor-Ausdrücke ist also ein zweistufiger Prozess. Zunächst müssen die geschachtelten Cursor in SQL erzeugt werden. Sehen wir uns eine solche Abfrage einmal an: select dname, loc, cursor(select job, cursor(select ename from emp n where n.job = e.job) from emp e where e.deptno = d.deptno) from dept d

Sie erkennen die harmonisierten Unterabfragen, die durch die Funktion cursor() zu eingeschachtelten Cursorn deklariert werden. Anschließend kann der Bericht erzeugt werden, indem drei ineinander geschachtelte Loop-Anweisungen die Cursor bearbeiten. Zur Bearbeitung der oben gezeigten Anweisung erstellen wir uns eine Prozedur, die einen Bericht ausgibt: SQL> create or replace procedure print_employee_report 2

as

3

type refcur is ref cursor;

4

department_cur refcur;

5

employee_cur refcur;

6

sql_stmt varchar2(400 char) :=

7

'select initcap(dname), initcap(loc),

8

cursor(select initcap(ename), initcap(job)

9

from emp e

10

where e.deptno = d.deptno)

11

from dept d';

12

dept_name dept.dname%TYPE;

13

dept_location dept.loc%TYPE;

14

job emp.job%TYPE;

15 16

436

name emp.ename%TYPE; begin

1452.book Seite 437 Donnerstag, 5. August 2010 3:55 15

Mengenverarbeitung mit Cursorn

17

open department_cur for sql_stmt;

18

loop

19

fetch department_cur

20

into dept_name, dept_location, employee_cur;

21

exit when department_cur%NOTFOUND;

22

dbms_output.put_line(

23

'Abteilung ' || dept_name ||

24

' in ' || dept_location);

25

loop

26

fetch employee_cur

27

into name, job;

28

exit when employee_cur%NOTFOUND;

29

dbms_output.put_line(

30

'Name: ' || name || ', Beruf: ' || job );

31

end loop;

32

dbms_output.put_line(' ');

33

end loop;

34

close department_cur;

35

end print_employee_report;

36

/

Prozedur wurde erstellt. SQL> exec print_employee_report; Abteilung Accounting in New York Name: Clark, Beruf: Manager Name: King, Beruf: President Name: Miller, Beruf: Clerk Abteilung Research in Dallas Name: Smith, Beruf: Clerk Name: Jones, Beruf: Manager Name: Scott, Beruf: Analyst Name: Adams, Beruf: Clerk Name: Ford, Beruf: Analyst Abteilung Sales in Chicago Name: Allen, Beruf: Salesman Name: Ward, Beruf: Salesman Name: Martin, Beruf: Salesman Name: Blake, Beruf: Manager Name: Turner, Beruf: Salesman Name: James, Beruf: Clerk

437

9.3

1452.book Seite 438 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

Abteilung Operations in Boston PL/SQL-Prozedur erfolgreich abgeschlossen. Listing 9.28 Verwendung von Cursor-Ausdrücken

Bitte beachten Sie, dass diese Konstruktion auf Cursorvariablen angewiesen ist, um die in SQL erstellten Cursor mit einem Handler zu versehen, mit dem in PL/ SQL gearbeitet werden kann. Daher deklariere ich zunächst zwei Cursorvariablen, denen anschließend die geschachtelten SQL-Cursor zugewiesen werden. Außerdem habe ich noch einige Variablen zur Aufnahme der Spaltenwerte deklariert. In Zeile 18 und 25 erkennen Sie die beiden geschachtelten Loop-Anweisungen. Die Zuweisung des in der SQL erzeugten geschachtelten Cursors zur Cursorvariablen employee_cur erfolgt innerhalb der inneren Schleife durch die FetchAnweisung in Zeile 26. Cursor-Ausdrücke eignen sich insbesondere beim Verschachteln mehrerer Tabellen, die zueinander in einer 1:n-Beziehung stehen. In diesem Kontext können Cursor-Ausdrücke implizit die Steuerung der geschachtelten Cursor übernehmen. Im Beispiel oben ist lediglich der employee_cur als geschachtelter Cursor beteiligt, doch lassen sich auch beliebig tief geschachtelte Konstruktionen denken. Natürlich geht solches SQL zulasten der Lesbarkeit, doch muss man andererseits sagen, dass die Verarbeitung dieser Cursor eher klar ist als das herkömmliche Pendant. Zudem ist diese Schachtelung schneller, weil sie vollständig auf der SQL-Seite durchgeführt werden kann. Geschlossen wird zum Ende der Bearbeitung lediglich der äußere Cursor. Dadurch werden implizit auch die geschachtelten Cursor freigegeben. Es ist ganz interessant, sich einmal die Ausgabe der SQL-Anweisung anzuschauen, die durch die Cursor-Ausdrücke erzeugt wird. Dadurch wird eventuell klarer, auf welche Weise die einzelnen Cursor ineinandergeschachtelt sind: SQL> select initcap(dname) dname, 2 initcap(loc) loc, 3 cursor(select initcap(ename) ename, 4 initcap(job) job 5 from emp e 6 where e.deptno = d.deptno) emp_cur 7 from dept d; DNAME LOC EMP_CUR -------------- ------------- -------------------Accounting New York CURSOR STATEMENT : 3 CURSOR STATEMENT : 3

438

1452.book Seite 439 Donnerstag, 5. August 2010 3:55 15

Mengenverarbeitung mit Cursorn

ENAME ---------Clark King Miller Research

JOB --------Manager President Clerk Dallas

CURSOR STATEMENT : 3

CURSOR STATEMENT : 3 ENAME JOB ---------- --------Smith Clerk Jones Manager Scott Analyst Adams Clerk Ford Analyst Sales

Chicago

CURSOR STATEMENT : 3

CURSOR STATEMENT : 3 ENAME JOB ---------- --------Allen Salesman Ward Salesman Martin Salesman Blake Manager Turner Salesman James Clerk 6 Zeilen ausgewählt. Operations

Boston

CURSOR STATEMENT : 3

CURSOR STATEMENT : 3 Es wurden keine Zeilen ausgewählt Listing 9.29 Darstellung eines Cursor-Ausdrucks in »SQL*Plus«

Die Cursor-Funktion wirkt wie eine Gruppenfunktion, erzeugt allerdings keine einzelne Zahl, sondern einen strukturierten Typ aus mehreren Zeilen, der anschließend als Cursor interpretiert und von PL/SQL gelesen werden kann. Als alternative Sicht sehen Sie in Abbildung 9.2, wie der SQL-Developer einen solchen Cursor-Ausdruck darstellt.

439

9.3

1452.book Seite 440 Donnerstag, 5. August 2010 3:55 15

9

Das Arbeiten mit Daten

Abbildung 9.2 Darstellung eines Cursor-Ausdrucks in SQL-Developer

440

1452.book Seite 865 Donnerstag, 5. August 2010 3:55 15

Index A Abfragegenerator 197 Abhängigkeitskette 396 Änderung der Spaltendeklaration 397 Änderung des Datentyps 397 Access Control List (ACL) 654, 671, 719, 749, 857 Advanced Queueing (AQ) 27, 29, 288, 478, 481, 743, 859 Advisory 244 Analytische Funktion 210, 548 anonymer PL/SQL-Block 250, 253, 269 Anwendungsarchitektur 22, 181 Apache 238 Apache Tomcat 239 Application Development Framework (ADF) 237 Application Express (APEX) 37, 86, 223, 237, 749, 792 APEX-Listener 239 Applikationsserver 85, 206 Arbeiten mit Daten 23 Arbeiten mit großen Datenstrukturen 24 Arbeiten mit XML 25 Architektur einer Applikation 96, 98 Archive-Log-Modus 64 ASCII 836 ASM 573 Assoziative Tabelle 314, 407, 446, 462, 519, 576 Count-Funktion 314 Delete-Funktion 315 Exists-Funktion 314 First/Last-Funktion 315 Prior/Next-Funktion 315 Atomizität 346, 351 Auditierung 243, 375 Fine Grained Auditing (FGA) 245 Ausführungsplan 110 Ausführungsrechte von PL/SQL-Blöcken 276 Ausgabeparameter 258 Ausnahme 씮 Exception

Authid-Klausel Aufruferrecht 277, 768 Aufrufrecht 277 Eigentümerrecht 276, 277 AutoCommit 172, 726 Automatic Database Diagnostic Monitor (ADDM) 479 Automatic Segment Space Management (ASSM) 573 autonome Transaktion 279, 346, 862 Autotrace 43 Autowert 116

B Backup & Recovery 95, 98, 104, 167, 244, 480 Base64-Kodierung 106 bedingte Anweisung 252 Beispieldatenbank 35 Beispielskripte 52 Benutzerdefinierte Typen 120 Benutzerprofil 168 Benutzerverwaltung 92 Best Practice Aufrufsystematik von Prozedurparametern 265 Benennungskonvention 389 Case- versus If-Anweisung 295 Case-Anweisung 292 Definition von Prozedurparametern 265 Funktion mit Ausgabeparameter 268 kaskadierende Trigger 353 Maskierung von Variablen 255 Schema & Tablespace 98 Speicherung von XML in der Datenbank 611, 614 Übergabe von Parametern mit Records 403 Verwendung von Blocktypen 281 Verwendung von SQL 517 Wahl eines Schleifentyps 304 XML-Datenbank 669 Binary Large Objects (BLOB) 77 Bindevariable 164, 174, 195

865

1452.book Seite 866 Donnerstag, 5. August 2010 3:55 15

Index

BLOB 씮 Datentyp Buchtipp Effective Oracle Security by Design 35 Mastering Oracle PL/SQL 35, 46 Thomas Kyte 34

C Change Data Capture (CDC) 478, 481 Character Set Scanner 125 Check-Summe 154 CLOB 씮 Datentyp Code Smell 747 Code-Generator 780 Connection Pool 759 Constraint 138, 205, 225, 233 Check 141, 233, 369 Fremdschlüssel 141, 143, 146 Primärschlüssel 346 Unique Constraint 142, 149 Cursor 164, 316, 445, 751 Attribut 319 Caching 319 Cursor-Ausdruck 435 Cursor-For-Schleife 323 Cursorvariable 328, 432 Definition 316 expliziter Cursor 423 impliziter Cursor 423 Kontrolle des Cursorzustandes 426 Lesen 318 Öffnen 317 parametrierter Cursor 322 schließen 319 schwache Cursorvariable 432 starke Cursorvariable 432 Top-N-Analyse 429 verteilter Cursor 753

D Data Access Layer (DAL) 759, 775 Data Dictionary 175 Data Warehouse 97, 103, 107 Database Access Descriptors (DAD) 239 Database Change Notification (DCN) 156, 158, 741 Database Configuration Assistant (DBCA) 654

866

Database Control 253 Database Link 84 Database Resident Connection Pool (DRCP) 78, 81, 84 Verwaltung 83 Data-Modeler 41 Dateisystem in der DB 119 Datenbank als Datenframework 748 Datenbankadministrator 98 Datenbank-Alert 244 Datenbankbenutzer 88, 759 Datenbank-Constraint 씮 Constraint Datenbank-Konfigurationsassistent 123 Datenbank-Link 117 Datenbankobjekt 씮 Oracle-Datenbank Datenbanktrigger 씮 Trigger Datenframework 182, 203 Datenmodelländerung 208 Integration von SQL und PL/SQL 208 Mächtigkeit von SQL 209 Performanz 204 Sicherheitsdomäne 205 Skalierbarkeit 205 syntaktische Prüfung von SQL 208 Datenintegrität 138, 205, 367, 760 Datenkonsistenz 22, 127, 137, 146, 150, 181, 182, 188, 225, 747, 753 Dead Lock 146, 152 explizites Sperren 150 Latch 166 Lock 165 Lock-Escalation 166 Lost Update 151 optimistisches Sperren 153, 157 pessimistisches Sperren 153, 155, 157 Sperrmechanismus 165 Sperrstrategie 157 Datenpumpe 181, 205 Datenschutz 194, 753 Datensicherheit 22, 97, 127, 166, 181, 182, 746 Denial of Service Attack 168 Datensicht 113, 203, 204, 206, 257, 358, 445, 765 Check-Option 358 materialisierte Datensicht 113 materialisierte Sicht 521, 525 Materialized View 113 user_source 468

1452.book Seite 867 Donnerstag, 5. August 2010 3:55 15

Index

Datentyp 223, 249, 251, 258, 282 Ableitung aus dem Data Dictionary 288 abweichende Datentypen 286 ANSI, DB/2 und SQL-DS 283 Any 284 anydata 481 anydataset 481 anytype 481 Assoziative Tabelle 288 Basistypen und Subtypen in PL/SQL 284 benutzerdefinierter Datentyp 283, 288 BFILE 559, 576 BLOB 559, 576 boolean 223, 251, 269, 285, 287, 519 CLOB 559, 575, 613 date 264 Datum 285 DBURIType 655, 657 HttpURIType 655, 710 HttpUriType 472, 712 httpUriType 481 LOB 217, 285, 559, 575, 752 long, raw, long raw 287, 559 Medientypen 284 NCLOB 559, 575 nested table 810 Numerische Datentypen 284 Objektoriente Datentypen 337 Oracle-definierte, komplexe Typen 283 Oracle-Spatial 284 Originäre Oracle-Datentypen 282 PL/SQL-exklusive Datentypen 287 Record 288, 794 ref_cursor 751 SQL-Datentypen 282 Table 283, 337, 341 URIType 284, 655 varchar2 und char 286 Varray 283, 337, 810 XDBURIType 656, 666 XMLType 284, 481, 606, 617, 642 Zeichentypen 285 Datentyp von Tabellenspalten 138 Datenverarbeitung 395 Datenzugriff über das Web 748 Prozedur über HTTP aufrufen 749 Webservices aus PL/SQL 750 Datenzugriff über Packages Integration von Geschäftsregeln 746

Kapselung von DML-Operationen 744 Vermeidung von Triggern 745 Datenzugriff über verteilte Cursor 751 Arbeit mit LOBs 752 Datumsfunktion 252 DBMS_Profiler 50 Ddefiners Right (DR) 씮 Authid-Klausel Dead Lock 씮 Datenkonsitenz Debugger 51 Denormalisierung 113 DIANA 33 DICOM 479, 481 Directory 577, 847, 853 Diskussion Abgrenzung von Zeitintervallen 377 Einsatz eines Schleifentyps 302 Einsatz von Triggern 391 Einsatz von Triggern für Defaultwerte 372 Implizer oder expliziter Cursor 423 Lösung des Mutating-Table-Problems 389 Refaktorisierung des Meldung-Objekts 795 Speicherung von Daten in objektrelationalen Tabellen 613 Speicherung von XML in der Datenbank 610 Variablen und das Data Dictionary 289 Wie und wo werden Fehler bearbeitet? 484 Zugriff auf Daten über View oder VPD 765 DRCP 씮 Database Resident Connection Pool (DRCP) Dynamisches SQL 249, 324 Bindevariablen 326 DBMS_SQL 330 Execute Immediate 325 mit Cursorvariablen 328 Sicherheit 333 SQL-Injection 333, 334 Vermeidung von SQL-Injection 336 Zuweisung von Bindevariablen 328

E Eigentümerrecht 768 Ein- und Ausgabeparameter 257, 258, 519 Enterprise Service Bus (ESB) 750 entfernte Ressource 182 Error Logging 216 Erweiterung von SQL 24, 266, 513, 517 Anforderungen an PL/SQL 519 deterministische Funktion 518

867

1452.book Seite 868 Donnerstag, 5. August 2010 3:55 15

Index

Externe Funktion 517 Funktion 519 Funktion existiert nicht 517 Gruppenfunktion erstellen 538 Nebenwirkungsfreiheit (Purity) 520 Optimizer Hint 520 SQL-Fähigkeiten 514 SQL-Lösung unverhältnismäßig 518 Exception 254, 255, 483 exec 254

F Factory 656 Fassade 204 Fehlerbehandlung 24, 483 Anwendungsfehler erstellen 495 benannte Fehler 489 Fehlerpackage 496 Fehlertrigger 505 nicht benannte Fehler benennen 494 Oracle-Fehler 483 raise_application_error 495 SQLCode 491 SQLErrm 491 Utility lmsgen 498 value_error 303 Fehlerbehandlungsteil 씮 Exception Framework 151 Fremdschlüssel 146 FTP 651 Funktion 115, 266, 513 analytische Funktion 225 deterministisch 111 Gruppenfunktion 223, 225 Nebenwirkungsfreiheit 224 Textfunktion 223 Umwandlungsfunktion 223 Zeilenfunktion 223

G generische Datenbankprogrammierung 182, 193, 196, 198, 205 Geschäftslogik 135, 229, 746, 747 gespeicherte Prozedur 씮 Prozedur Gruppenfunktion 513, 538 Arbeitsweise 539 Initialisierung 539, 540

868

Iteration 539, 540 Terminierung 539, 541 Zusammenführung 539, 541 Gültigkeitsbereich von Variablen 255

H Hash 163, 737 Hintergrund Objektorientierung 541 Rechte von PL/SQL-Code 552 Historisierung von Daten 226 HTML 603 HTTP 612, 651, 726, 748, 749

I I18N 777 imp 124 impd 124 Impedance Mismatch 22, 183 Cache 188 Datensuche 184 Identität 183 Koppelung von Logik und Daten 191 Lazy Load 187 Lesestrategie 186 Objekthierarchie 188 referenzielle Integrität 192 Statement of Truth 184, 191 Table per Class 189 Table per Class Family 190 Vererbung 188 implizite Konvertierung 290 Index 95, 100, 101, 105, 142 Benutzung von Indizes 107 Binärbaum-Index 107, 109 Bitmap-Index 107 funktionsbasierter Index 107, 108, 111, 149, 225, 521, 523 Index-Range-Scan 109, 111 Reverse-Key-Index 107, 110 Unique-Index 112, 143 Initialisierung eigener Fehler 280 Integration von Oracle in Applikationen 26, 725 Integration von SQL in PL/SQL 249 Invokers Right (IR) 씮 Authid-Clausel

1452.book Seite 869 Donnerstag, 5. August 2010 3:55 15

Index

J Java 478 Java Message Service (JMS) 859 Java Naming and Directory Interface (JNDI) 864 Java Server Faces 748 JDBC 171, 726, 751, 864 Job 244 Journaled Filesystem 574

K Kapselung 182 Kollektion 249, 310, 407 spärlich besetzt 410 Kompileranweisung 279 Kompilieren 115 Komponententest 52 konditionale Kompilierung 295, 843, 846 Abfrage-Direktive 297 Auswahl-Direktive 297 Error-Direktive 299 Konstruktormethode 338 Kontrollstruktur 249, 291 Case-Anweisung 292, 296 Case-Anweisung (bedingt) 294 Case-Anweisung (einfach) 293 Einfache Schleife 300 For-Schleife 301 if - then - else-Anweisung 291 konditionale Kompilierung 295 Nicht empfohlene Anweisungen 307 Schleifenoptionen 302 While-Schleife 303

L Language for ADA (DIANA) 465 Latch 166, 170, 171 Lazy Load 201 LDAP 478, 759 Lesekonsistenz 65, 128, 129, 149, 194, 202, 348, 354, 368, 735 Leserecht 91 LOB 118, 559, 752, 753, 778 API für BFILE 583 BFile 118 BLOB 118

CLOB 118 Einsatz in der Datenbank 560 LOB als Parameter 571 LOB als PL/SQL-Variable 565 Long-Datentyp 119 mit Daten füllen 563 NCLOB 118 Null-LOB, leeres LOB 561 persistentes LOB 565, 567 Schreibzugriff 579 Secure Files 572 SQL-Semantik 567 Technische Struktur 560 Variablendeklaration und -initialisierung 566 Verarbeitung mit dbms_lob 578 Lock 165, 170, 171 Log4J 27 log4plsql 777, 781, 782, 864 Logging-Package 27 lost update 727

M Mächtigkeit von SQL Fazit 221 Maschinenabhängiger Bytecode (M-Code) 465 Maskierung von Variablen 255 Massenverarbeitung von Daten 409 Bulk-Select 414 Fehlerkontrolle 413 materialisierte Datensicht 씮 Datensicht M-Code 씮 Pseudocode (P-Code) Mengenverarbeitung mit Cursorn 423 Message Oriented Middleware (MOM) 859 Model-View-Control (MVC) 748 MoneyType 697 Implementierung 699 Implementierung des Package coa_money 705 Package-Körper coa_money 707 Rechteverwaltung in Oracle 11g 718 Typkörper 701 Typspezifikation 699 Vererbung 721 Vorüberlegungen 697 Multi-Table-Insert 746 Mutating-Table-Problem 520, 745

869

1452.book Seite 870 Donnerstag, 5. August 2010 3:55 15

Index

N Namenskonvention 257 National Language Support (NLS) 122, 124 Längensemantik 125 National Language Support (NLS) 씮 Zeichensatzkodierung bei Oracle Nebenläufigkeit 379 .NET Framework 748 Normalisierung 113 Nullwert 112

O Obektrelationales Mapping (ORM) 200 Cache 201 Hibernate 201 Kapselung der SQL-Dialekte 201 Lazy Load 201 Mapping von Objekten auf Tabellen 200 Oracle Top Link 201 Transaktion 201 Object Change Notification (OCN) 742 Objekt-ID (OID) 183 Objektorientierung 25, 27, 120, 181, 273, 395, 604, 681, 748, 778, 782 abstrakte und finale Klasse 687 Alles ist ein Objekt 684 Auswirkung auf die Datenbankprogrammierung 693 Best Practices 723 Einführung 683 Einsatz von Objekten als Triggerersatz 392 extern implementierte Methode 697 Gruppenfunktion in PL/SQL 540 Instanziierung 338 Klassenstruktur 691 Konstruktorfunktion 696 Member-Methoden 696 objektrelationale Tabelle 613 statische Methode 688, 696 Typ 480, 695 Typkörper 695 Typspezifikation 695 Vererbung 686, 695 Vergleich mit relationalem Weltbild 689 Objektprivileg 91, 167 Objektrelationales Mapping (ORM) 182, 197, 200 OLE-DB 117

870

Online Analytical Processing (OLAP) 60, 479 Online Transactional Processing (OLTP) 85, 87, 97 Online-Dokumentation 29, 249 2-Day Administration Guide 37 AskTom 33 Concepts-Guide 31 Data Warehousing Guide 34 New Features Guide 32 PL/SQL Language Reference 33 PL/SQL Packages and Type Reference 34 SQL*Plus Quick Reference 40 SQL*Plus User’s Guide 40 XML Developers Guide 34 Open Database Connectivity (ODBC) 117 optionale Parameter 264 Oracle Advanced Security 573 Oracle Advisor 479 Oracle by Example (OBE) 30 Oracle Data Mining 479 Oracle Express Edition 36 Oracle Forms und Reports 237 Oracle Heterogenous Services 117 Oracle Managed Files (OMF) 573 Oracle Packages 34 Oracle Packages 씮 Package Oracle Spatial 29 Oracle Streams AQ 864 Oracle-Datenbank 21, 88, 99 Anmeldung 68 Archive Process 64 Aufbau der Datenbank 21 Backup & Recovery 66, 67, 84 Checkpoint 63 Connection 71 Data Dictionary 65 Database Block Writer 62 Data-Block-Buffer-Cache 58 Data-Dictionary 113, 115 Data-Dictionary-Cache 60 Datenbankblock 136 Datenbankblocknummer 106 Datenbankjob 114 Datenbankobjektnummer 106 Datendatei 55, 65, 67 Datendateinummer 106 Dedicated-Server-Verbindung 78, 85 Default-Pool 58 Dispatcher 79, 80

1452.book Seite 871 Donnerstag, 5. August 2010 3:55 15

Index

DRCP 87 Eazy Connect (EZConnect) 73, 79 filesystem_like_logging 574 Fixed SGA 59 Foreign-Key-Constraint 21 Full-Table-Scan 100 Grundlagen 55 High Watermark 100 Hintergrundprozess 56, 60 indexorganisierte Tabelle 791 Init-Ora-Datei 67 Installation 68 Instanz 55, 69, 96 Java-Objekt 115 Java-Pool 57 JDBC 75 JDBC-Treiber 72 Keep-Pool 58 Kontrolldatei 55, 67, 69 Large-Pool 57 LDAP 72, 77 Library-Cache 60, 162 Listener 70, 79, 169 listener.ora 73 Log-Switch 63, 66, 67 Log-Writer 62 materialisierte Sicht 480 Mount der Datenbank 69 Net8-Protokoll 242 nologging 574 Null-Pool 58 ODP.NET 75 Öffnen der Datenbank 69 Optimizer 108, 160 Oracle Net Service 72 Oracle-Connection-Manager 72 Oracle-Homeverzeichnis 67 Oracle-Net-Services 72 Overflow-Segment 793 Parameter 96 Parameterdatei 67 Passwortdatei 67, 68 physical reads 44 physikalische Dateien 65 PL/SQL-Objekt 115 PMON 156 Process Global Area (PGA) 59, 79 Process Monitor 61 Queue 80, 86, 860 Quota 93

Recovery Manager 57 Recycle-Pool 59 Redo-Log-Archiv 66 Redo-Log-Buffer 59, 62, 66 Redo-Log-Datei 55, 63, 66, 67 RMAN 169 Rollback-Segment 133 Row-ID 100, 105, 106, 111, 730 Savepoint 351 Schema 87 Secure Files 572, 614 Serverprozess 79 Session 71 Shared Server 239 Shared-Pool 57, 59 Shared-Server-Parameter 81 Shared-Server-Prozess 80, 81 Shared-Server-Verbindung 79, 80 SID 74 Slave-Prozess 64 Sonstige 115 Speicher-Pool 57 Speicherstruktur 109 Sperre 368 SPfile-Datei 67 sqlnet.ora 73 Start der Datenbank 69 Streams-Pool 57 System Global Area 55, 57, 67 System Monitor 61 System-Change-Number (SCN) 155, 737 Systemtabelle 65 Tablespace 87 TCP/IP 74 temporärer Tablespace 565 TNS 73, 78 tnsnames.ora 73, 78, 80, 83, 242 Transportabler Tablespace 480 Treiber 72 User Global Area (UGA) 79 Verbindungaufbau 70 Verbindungsaufbau 84 Verteilte Verbindung 85 Webserver 72, 654 XDB 76 XMLType 120 Oracle-Magazine 30 Oracle-Spatial 479 Organisation von PL/SQL-Code 256 ORM 씮 Obektrelationales Mapping (ORM)

871

1452.book Seite 872 Donnerstag, 5. August 2010 3:55 15

Index

P Package 23, 115, 229, 250, 272, 441, 745 Abhängigkeitskette 458 apex_* 476 Aufruf von Prozeduren und Funktionen 276 ctx_* 479 Datenbank-Utilitys 475 dbms_* 252 dbms_addm 479 dbms_advisor 479 dbms_application_info 477, 789 dbms_aq 862 dbms_aq_* 478 dbms_aqadm 860 dbms_assert 336, 477 dbms_backup_restore 480 dbms_cdc_publish 478 dbms_cdc_subscribe 478 dbms_comparison 479 dbms_connection_pool 478 dbms_crypto 475, 521, 698, 762, 766, 768 dbms_data_ming_* 479 dbms_ddl 467, 469 dbms_debug 51, 477 dbms_describe 477 dbms_epg 477 dbms_errlog 217, 477 dbms_fga 245 dbms_java 478 dbms_job 478 dbms_ldap 478, 480 dbms_lob 562, 566, 575, 577, 578, 590, 629, 843 dbms_meta_data 479 dbms_metadata 243 dbms_mgd_id_util 479 dbms_monitor 477, 480 dbms_mview 34, 480 dbms_network_acl 719 dbms_network_acl_utility 480 dbms_obfuscation_toolkit 475, 698 dbms_odci 477 dbms_olap 479 dbms_output 34, 252, 276, 475, 597, 783, 855 dbms_pipe 478 dbms_profiler 50, 477 dbms_random 303, 475, 520

872

dbms_rcvcat 480 dbms_rcvman 480 dbms_scheduler 478 dbms_server_alert 479 dbms_shared_pool 479 dbms_space_* 479 dbms_spm 480 dbms_sql 330, 468, 480 dbms_sqldiag 480 dbms_sqlpa 479 dbms_sqlune 480 dbms_stats 480 dbms_streams_* 478 dbms_system 855 dbms_trace 477 dbms_tts 480 dbms_utility 344, 420, 475, 491 dbms_version 291, 475 dbms_xdb 253, 660 dbms_xdb_version 677 dbms_xmldom 641, 643 dbms_xmlgen 621, 625, 631, 647 dbms_xmlindex 650 dbms_xmlparser 641, 643 dbms_xmlquery 647 dbms_xmlsave 615, 647 dbms_xmlschema 650, 665 dbms_xmlstore 615, 647 dbms_xmltranslations 650 dbms_xplan 480 dbms_xslprocessor 641 htf 477 htp 477, 597 Implementierungsteil 274 Initialisierungsprozedur 275, 444, 445 Konstante 458 Körper 272, 274 Oracle-Packages 470 owa_* 476 owa_cookie 476 owa_opt_lock 476 Packagekörper 443 Packagespezifikation 272, 442, 447 sdo_* 479 sem_apis 477 sem_perf 477 standard 286, 473, 489 Trennung von öffentlicher und privater Logik 442

1452.book Seite 873 Donnerstag, 5. August 2010 3:55 15

Index

Überladung 452 util_dbms 816 utl_* 475 utl_compress 475 utl_dbws 475 utl_encode 475 utl_file 475, 847, 852 utl_http 476, 749 utl_i18n 476 utl_inaddr 476 utl_lms 476, 494, 503, 810 utl_mail 295, 476, 698, 857 utl_pipe 859 utl_smtp 295, 476, 698 utl_url 476, 477 utl_utcp 476 Verschlüsselung von Code 464 Verwendung 441 Vorteile 272 Vorwärtsdeklaration 276 wpg_docload 472 Wrap-Utility 465 Parameter 256 nls_language 836 session_max_open_files 584 Parameterzuweisung 263 explizit 263 positionell 263 Passwort 168 P-Code 씮 Maschinenabhängiger Bytecode (M-Code) Performanz 104, 107, 136, 181, 182, 196, 202, 204, 272, 427, 431, 765, 848 Datenbank-Constraints 143 Einfluss der Programmierung 169 Implementierung eines Tests 171 Latching 128 Locking 128 Mengenverarbeitung 177 Sperren 170 Umgebungswechsel 176 Pivotierung 516 PL/SQL 17, 21, 23, 29 Blockstruktur 23 Syntax 23 Tuning 33 PL/SQL im Einsatz 24 PL/SQL Server Pages 749

PL/SQL-Befehl %RowType 289 %Type 289 authid current_user 278 Authid-Klausel 277 begin 251, 252 bult_exceptions 413 case 291, 292 continue 309 declare 251, 252, 269 default 264 deterministic 520 end 251 exception 251, 842 execute immediate 325 exit 301 finally (nicht existent!) 427 for - cursor - loop 323 forall 410 For-Loop 301 for-reverse-loop 303 function 267 goto 309 if - then - else 291 in 258 in out 258 in out nocopy 258 label 307 Loop 300 nocopy 258 nocopy-Klausel 571 out 258 package 273 parallel enable 521 pipe row 417 pipelined 416 plsql_warnings 572 pragam autonomous_transaction 280 Pragma-Klausel 279 Pseudospalte row 399 Pseudovariablen new/old 270 raise_application_error 370, 495, 498 ref_cursor 751 return 267 sqlcode 491, 501 sqlerrm 252, 491 when others 484 where-current-of-Klausel 730 While-Loop 303 Zuweisungsoperator 251, 264

873

1452.book Seite 874 Donnerstag, 5. August 2010 3:55 15

Index

PL/SQL-Befehl 씮 Kompileranweisung PL/SQL-Block 250 Ausführungsteil 250 Deklarationsteil 250 Ende 250, 256 Fehlerbehandlungsteil 250 PL/SQL-Developer 41, 50 PL/SQL-Grundlagen 33 PL/SQL-Profiler 789 PL/SQL-Referenz 29 Pragma autonomous_transaction 346, 857 exception_init 535, 846 restrict_references 521 Praxisbeispiel Ableitung einer Variablen aus dem Data Dictionary 289 Ableitung eines Record aus dem Data Dictionary 312 ACL für E-Mail-Versand administrieren 858 Administration der XDB 654 Administrationsaufgabe 253 Advanced-Queueing-Tabelle anlegen 860 Aktualisierung von Daten mit Records 399, 400 Analyse der XML-Datenbank 652 Analytische Funktion 211 anonymer Block 251 API für dbms_crypto 767 API zum Laden von LOBs aus der Datenbank 584 API zum Lesen von LOBs aus der Datenbank 592 Arbeit mit hierarchischen Objekten 801 Assertionsmethoden 486 Auditierung 376 Aufruf einer Prozedur mit Ausgabeparameter 261 Ausgabe eines LOB über http 597 autonome Transaktion 280 bedingte Case-Anweisung 294 bedingter Primärschlüssel 793 Benennung eines Fehlers 489 Benenung eines Fehlers 494 Berechnung der Fakultät 528 Bindevariable für Wertelisten 419 Bindevariablen 163 Check-Constraint 146 CLOB in Datei schreiben 844

874

Code-Generator für Gruppenfunktionen 549 Compound-Trigger 355 Cursorausdruck 436 Cursor-For-Schleife 323 Cursorvariable 433 Cursorvariable als Parameter 434 Datenbank-Link 117 Datenbanktrigger 270 Datenbanktrigger after logon 359 Datensicherheit durch Trigger 233 Datensicht mit Check-Option 358 dbms_metadata 243 Definition einer Assoziativen Tabelle 315 Definition eines parametrierten Cursor 322 Deklaration einer assoziativen Tabelle 407 Deklaration einer Nested Table 341 Deklaration eines Cursors 318 Deklaration eines expliziten Records 401 Deklaration eines Packages 273 Deklaration eines Records in einem Package 402 Deklaration eines VArray 338 Deklaration von Datentypen im Package standard 286 Ein LOB mit Daten füllen 563 Ein Objekt als Ersatz für einen Record 406 einfache Case-Anweisung 293 einfache Funktion 266 einfache If-Anweisung 292 einfache Prozedur 256 einfache Record-Definition 311 einfache While-Schleife 303 einfacher Package-Körper 274 Einfluss der Programmierung auf die Performanz 169 Einfügen von Daten mit Records 398 Error Logging 216 Erstellung einer ACL 719 Erstellung einer Gruppenfunktion 542 Erstellung einer sicheren Anwendung 762 Erzeugun von XML aus einem Objekt 625 Erzeugung einer ACL 673 Erzeugung einer schemabasierten Tabelle 667 Erzeugung von XML aus hierarchischen Abfragen 630 Erzeugung von XML mittels dbms_xmlgen 622 Execute Immediate mit Bindevariable 326

1452.book Seite 875 Donnerstag, 5. August 2010 3:55 15

Index

Execute Immediate mit Cursorvariable 329 Execute-Immediate 325 explizite Parameterübergabe 263 Fakultätsfunktion 300, 301 Fehler initialisieren 280 Fehlerbehandlung über einen Fehlertrigger 505 Fehlerdeklaration mit lmsgen 499 Fehlerpackage 496 Fehlerstack 492 Fine Grained Auditing (FGA) 245 For-Schleife 306 Funktion mit Ausgabeparameter 267 Funktionsbasierter Index 111 geschachtelter Block 254 geschachtelter Record 312 Hierarchische Abfrage 214 Hilfsfunktion für die Arbeit mit LOB 584 If-Anweisung 292 Implementierung des Default-Meldungsmoduls 804 Implementierung des Meldung-Objekts 795 Implementierung des Message-Grundmoduls 803 Implementierung eines Packages 444 Impliziter versus expliziter Cursor 424 Index Range Scan 109 Instanziierung eines Objektes nach Namen 817 Instanziierung eines Objekts 339 Instead-Of-Trigger 357, 381 Iteration über eine assoziative Tabelle mit Textschlüssel 817 Jurassic-Park-Phänomen 144 konditionale Kompilierung 296, 297, 299, 845 Konstanten-Package 459 Lesen einer Ressource aus dem Internet 713 loadpsp 241 LOB 629 LOB, Null-LOB. leeres LOB 561 LOB-Variable deklarieren 566 Lösung des Mutating-Table-Problems 384 Maskierung von Variablen 255 Massenverarbeitung mit assoziativer Tabelle 409 Massenverarbeitung mit Bulk-Kontrolle 412 Massenverarbeitung mit Bulk-Select 415

Massenverarbeitung von Daten mit Fehlerkontrolle 413 Materialisierte Sicht 114 Meldungstabelle 792 Merge-Anweisung 835 MoneyType 697 Mutating-Table-Problem 353 Objekthierarchie erstellen 722 optimistisches Sperren 733 optimitisches Sperren mit SCN 738 ORA_ROWSCN 154 Parametertabelle 463, 550, 790 Parametertabelle über View und Synonym 785 pessimistisches Sperren 727 PL/SQL Server Pages 240 PL/SQL Web Toolkit 239 PL/SQL-Package dynamisch erzeugen 844 Probleme mit impliziter Konvertierung 290 Prozedur mit Aufruferrechten 278 Prozedur mit Ausgabeparameter 260 Prozedur mit eingebetteter Prozedur 262 Prozedur mit optionalem Parameter 264 Prozedur mit Parameterm 259 Prozedur mit problematischen Parametern 265 Prozedur zur Datenänderung 229 Prüfung auf vorhandene Daten 425 Public-Synonym erzeugen 855 Record mit SQL-Returning-Klausel 404 Refaktorisierung der Fakultätsfunktion 484 Registrierung eines XML-Schemas in der XDB 663 Relationale Daten aus XML mittels SQL/XML extrahieren 636 Scheduler und Job 244 Schemata 90 Schlechte Schleife 305 Schleife mit Label 307 Schreibzugriff auf ein LOB 579 Secure Files 573 Selektiver Primärschlüssel 146 Sequenz 116 Spezifiaktion eines Packages 442 SQL zur Lösung prozeduraler Probleme 515 SQL/XML 609, 617 SQL/XML-Anweisung 839 SQL/XML-Geschwindigkeitstest 619 SQL-Anweisung call 254

875

1452.book Seite 876 Donnerstag, 5. August 2010 3:55 15

Index

SQL-Anweisung zum Pivotieren von Spalten 819 SQL-Injection 333, 335 Synonym 117 Tabellenfunktion als virtuelle Tabelle 420 temporäres versus persistentes LOB 567 Top-N-Analyse 429 Trigger 226, 235 Trigger before drop 390 Trigger on servererror 391 Trigger zur Datenkonsistenzprüfung 369 Trigger zur Erzeugung von Defaultwerten 371 Trigger zur Historisierung von Daten 378 Trigger, um Reihenfolge von Werten zu garantieren 372 Übergabe beliebig vieler Parameter an eine Methode 810 Überladung von Methoden 453 Umwandlungsfunktion 224 Verschlüsselung von Code mit dbms_ddl 468 Verschlüsselung von Code mit Wrap-Utility 465 Verwendung der empty_clob()-Anweisung 564 Verwendung der nocopy-Klausel 572 Verwendung der Pseudovariablen 271 Verwendung der URI-Factory 657 Verwendung der XMLTable()-Anweisung 633 Verwendung des DBURIType 657 Verwendung des Package dbms_xdb 660 Verwendung des Packages dbms_crypto 763 Verwendung des Sessionkontextes 764 Verwendung einer Assoziativen Tabelle 315 Verwendung einer Nested Table 341 Verwendung einer Tabellenfunktion 416 Verwendung eines BFILE 577 Verwendung eines Cursors 320 Verwendung eines objektorientierten Typen in SQL 693 Verwendung eines Record 313 Verwendung eines Varray 339 Verwendung von Aufruferrechten 768 Verwendung von BFILE 583 Verwendung von dbms_sql 331 Verwendung von dbms_xdb_version 677 Verwendung von LOB 569 Verwendung von nicht-SQL-Datentypen als Eingabeparameter 529

876

Verwendung von Optimizer Hints 522 Verwendung von SQL/XML 615 Verwendung von XMLType 606 Wrapper für utl_lms 501 XML-Aktualisierung mit dbms_xmlstore 648 XML-Programmierung mit dbms_xmldom 642 XMLType-funktionsbasierter Index 610 XQuery-Abfrage 635 XSQL Publishing Framework 242 Zugriff auf Daten mit WebDAV 651 Praxisbericht Abfragegenerator 198 Datenkonsistenz 232 effizientes SQL 194, 195 generische Datenbankprogrammierung 198 Grenzen von XML-Verarbeitung 605 Konsistene Verwendung von Datentypen 140 Modellierung von XML in der Datenbank 610 objektrelationales Mapping 197 Spaltentyp 138 Tablespace 94 Transaktion 194 Unnötige Programmierung 470 Primärschlüssel 101, 108, 141 Programmiermodell 151 Programmierung 223 Administrationsunterstützung 242 Anwendungsprogrammierung 236 Application Express (APEX) 237 Auditing 245 Client-seitiges PL/SQL 237 clientseitiges PL/SQL 236 Datenkonsistenz 225 Datenkonsistenz mittels PL/SQL 232 Datensicherheit 233 Datensicherung 245 Datenzugriff über PL/SQL 229 Embedded PL/SQL Gateway 238 erweiterte Datenbankfunktionalität 223 mod_plsql 238 PL/SQL Gateway 238 PL/SQL Server Pages 238, 240 PL/SQL Web Toolkit 238, 239 PL/SQL-Skript 243 Webanwendungen in PL/SQL 236

1452.book Seite 877 Donnerstag, 5. August 2010 3:55 15

Index

Webanwendungen mit PL/SQL 238 XSQL Publishing Framework 238, 241 Programmierung der Datenbank 22 Programmierung von Triggern 23 Prozedur 115, 204, 256, 747, 753 Parameter 257 Spezifikation 231 Pseudocode (P-Code) 465 Pseudospalte column_value 419, 421 level 631 ora_rowscn 737 user 520

Q Query Result Change Notification (QRCN) 742

R Radio Frequency Identification (RFID) 479 Record 310, 395, 462 Ableitung aus dem Data Dictionary 312 Definition durch das Data Dictionary 395 expliziter Record# 401 Insert- und Update-Anweisung 398 Objekt als Alternative 406 Returning-Klausel 404 Recovery Manager (RMAN) 84, 480 Recovery Manager (RMAN) 씮 Oracle-Datenbank Redundanz 167 referentielle Integrität 137 Rekursion 537 Relationales Datenbankmanagementsystem (RDBMS) 167, 181, 193, 196, 198 Remote Procedure Call (RPC) 604 RFID 481 Rollenkonzept 167 Round-Half-Even-Verfahren 714 Rules and Expressions 481 RunStats 45, 170

S Schachtelung von Blöcken zur Fehlerbehandlung 254 Scheduler 243, 244

Schema 88, 91, 92, 97, 168, 277 Schleifenkonstruktion 254 Schreibkonsistenz 128, 132 Schreibrecht 91, 229 Secure Application Role (SAR) 760, 762, 765 Secure Files 119, 752 Semaphore 166 Sequenz 116 Sequenz 씮 Autowert Serialisierung 166 Service Oriented Architecture (SOA) 604, 748, 750 Session 157, 161, 732, 848 Sessionkontext 206 USERENV 206, 233, 234 Sessionvariable 103 Sicherheitsdomäne 168, 205 Skalierbarkeit 196, 202, 205 Smell 796 SOAP 749 Sperren von Daten 726 Database Change Notfication (DCN) 727, 741 optimistisches Sperren 727, 733, 736 pessimistisches Sperren 727 SQL 17, 29 ANSI-Standard 127 hierarchische Abfrage 212 Isolation-Level 129, 130, 131 ISO-Standard 127 SQL Developer 249, 251, 252 SQL*Loader 353 Direct-Path-Load 353 SQL*Plus 38, 41, 150, 249, 251, 252, 338, 775 set serveroutput on 252 Zeichen / 253 SQL/XML 604, 610, 615, 617, 618, 629, 631, 638, 661, 675, 711 SQL-Anweisung 79, 80, 113, 158 after update 270 alter session 334 analytische Funktion 209 analytische Funktionen 514 ANSI-Standard 127 Atomizität 216 Ausführen (lesend) 160 Ausführen (schreibend) 162

877

1452.book Seite 878 Donnerstag, 5. August 2010 3:55 15

Index

avg 193 bfilename() 578 Case 112 case 292, 515 cast 625 column_value 607 columns-Klausel 712 commit 346 create Index 107 create or replace 257 create Sequence 116 create session 698, 759 cursor 422, 435 DDL-Anweisung 520 debug any procedure 51 debug connect session 51 decode 291, 516 delete 100, 104, 345 distinct 576 DML-Anweisung 112, 133, 225, 345 drop 757 empty_clob() 564, 578 equals_path 675 Error-Logging 209 explain plan 41 extract 370 for each row 347 for update-Klausel 729 full join 787 group by 576 hierarcische Abfrage 209 identified-using-Klausel 762 insert 102, 116, 345 intersect 576 ISO-Standard 127, 198 Log-Error-Klausel 514, 746 map-Klausel 697 merge 133, 345, 746, 835 minus 576 multiset 625 new 721 not-final-Klausel 803 not-instantiable-Klausel 803 nowait-Klausel 729 Optimierung 159, 160, 162 order by 576 order-Klausel 697 Parsen 159 Pivot-Klausel 516

878

Projektion 186 reguläre Ausdrücke 376 replace 257, 567 returning-Klausel 404 rollback 346 rowdependencies-Klausel 738 scn_to_timestamp 739 Select for update 156 Set Transaction 133 substr 567 sys_context 764 sys_refcursor 435 sysdate 520 systimestamp 370 table() 607, 637 truncate 101, 757 under-Klausel 722 union / union all 576 update 153, 230, 345 updateXML 638, 675, 839 URIFactory 656 with-grant-option-Klausel 764 xmlagg 618, 633 xmlattributes 616 xmlelement 616 XML-Erzeugung mit SQL 515 xmlforest 616 xmlsequence 637 xmlTable 634, 711 XMLTable() 632, 633 SQL-Developer 40 SQL-Skriptdatei 124, 243 utlxplan.sql 41 Stored Procedure 씮 Prozedur Synonym 117 Syntax 249, 250 Systemprivileg 88, 167

T Tabelle 90, 99 exklusiv sperren 369 Full Table Lock 152 Full Table Scan 108, 139, 152 Global Temporary Table 99, 102 Hash-Partition 104 Heap Organized Table 99 Heap-Organized-Table 99, 109 Index Organized Table 99, 101

1452.book Seite 879 Donnerstag, 5. August 2010 3:55 15

Index

List-Partition 104 Partitionierte Tabelle 103 Pseudospalte 105 Pseudospalte ORA_ROWSCN 154 Range-Partition 103 Tabellenfunktion 344, 415 Tablespace 88, 89, 93, 94, 168 Quota 168 Read Only Tablespace 94 Temporary Tablespace 94 TCP/IP 72 temporäres LOB 567 Tiefenkopie 571 TKProf 46 tnsnames.ora 117 tnsping 74 Toad 41 Token 761 TopLink 733 Transaktion 22, 61, 62, 65, 127, 132, 165, 182, 194, 202, 231, 346, 520, 726, 729 autonome Transaktion 279 Transaktionslog 133, 136 Transaktionsschutz 128 Unit of Work (UoW) 136, 201, 732 Verteilte Transaktion 118 Trigger 115, 147, 225, 245, 269, 279, 345, 520 Anforderungen 271 Anweisungstrigger 347 Anwendungstrigger 237 Auditierung durch Trigger 375 Auslösereihenfolge 352 Auslösung 351 benutzerbezogene Ereignisse 364 Compound-Trigger 355 Compound-Trigger und Mutating-Table 384 Datenbankereignis 245, 345, 362 Datenbanktrigger 359 Datenintegrität 367 DDL-Ereignis 389 Defaultwerte setzen 371 Definition 269 DML-Ereignis 369 DML-Trigger 345 Einsatzbereiche 367 Ereignisattribute 360 Erweiterung der Datenkonsistenzprüfung 369

follows-Klausel 352 Historisierung von Daten 377 Instead-Of-Trigger 357, 381 kaskadierende 353 konditionale Ausführung 349 Körper 350 Mutating-Table-Problem 353, 368, 379, 395 Pseudovariablen new/old 350 Spezifikation 349 Systemereignis 225, 391 Update-Reihenfolge festlegen 372 when-Klausel 349 Zeilentrigger 347 zirkuläre Triggerdefinition 354

U Überladen von Prozeduren und Funktionen 272 Überladung 452 Überladung 씮 Package Umgebungswechsel 224, 517 Unicode 575 Unit of Work (UoW) 씮 Transaktion unverzerrtes (mathematisches) Rundungsverfahren 701 URL 577, 710

V Variable 251 View 씮 Datensicht Virtual Private Database (VPD) 765

W WebDAV 72, 76, 416, 651, 654, 671 WebService 182, 225, 604, 750, 753, 781 Weiterführende Literatur 34 Workshop 26 Workshop Logging-Package 777 Architektur und Überblick 778 Ausgabemodul Alert-Datei 855 Ausgabemodul E-Mail 857 Ausgabemodul JMS 859 Ausgabemodul Tabelle 856 Ausgabemodul Trace-Datei 847 Ausgabemodul-Objekt 782

879

1452.book Seite 880 Donnerstag, 5. August 2010 3:55 15

Index

Implementierung 790 Implementierung der Log-Admin-PackageSpezifikation 830 Implementierung der Logging-Package-Spezifikation 811 Implementierung des Kontextes 808 Implementierung des Log-Admin-PackageKörpers 832 Implementierung des Log-Admin-Packages 828 Implementierung des Logging-Package-Körpers 814 Implementierung des Logging-Packages 811 Implementierung des Meldungsgrundmoduls 800 Implementierung einer Parameterliste 809 Implementierung Meldungstabelle 791 Implementierung Parametertabelle 790 Kontext 781 Meldung-Objekt 780 Meldungsobjekt 794 Meldungspackage 789 Tabellen 784 Test des Logging-Packages 827 Weitere Ausgabemodule 846 Workshop Sichere Anwendung 757 Archtitektur 758 Aufsetzen der Schemata 762 Logon-Prozedur 761 Packages 766 Projektbeschreibung 757 Test 772 Token 770

X XLIFF 829, 838, 840 XML 25, 27, 120, 125, 241, 242, 603, 750, 752, 778, 829 BinaryXML 613 DOM-Baum 605, 615, 629, 637, 638 Erzeugung aus Objekten 624 Erzeugung durch dbms_xmlgen 622 Erzeugung von XML aus hierarchischen Abfragen 629 For-Let-Order By-Where-Return (FLOWR) 632 getnumberval()-Anweisung 609 Namensraum 639

880

Null-Namespace 668 Oracle-Parser 640 Packages zur Erzeugung und Speicherung von XML 647 Paginierung von XML-Abfragen 631 PL/SQL-Packages für XML 640 Programmierung mit SAX 638 Relationale Daten aus XML extrahieren 631 SAX 615 Simple API for XML (SAX) 639 Sonstige PL/SQL-Packages 650 Speicherung ind der Datenbank 613 sys$nc_rowinfo 607 Verarbeitung mit PL/SQL 638 Weißraum 639 wohlgeformt 613 XML aus relationalen Daten erzeugen 615 XML Schema Definition Language (XSD) 603 XPath 605, 609, 632 XQuery 632 XSD 613, 650, 662, 667 XSL-FO 604, 640 XSL-T 604 XSLT 628, 632, 638 XML Database (XDB) 72, 76, 239, 416, 478, 605, 641, 651 ACL 671 Arbeit mit ACLs 673 Dokumente per Drag & Drop einfügen 659 Dokumente per PL/SQL einfügen 660 Dokumente verwalten 659 Einführung 652 Registrierung eines Schemas 663 schemabsierte Tabelle 666 Speicherung mit XML-Schema 662 Versionierung von Ressourcen 676 Verwaltung von Dokumenten 654 Zugriffsschutz und Sicherheit 670 XML Localization Interchange File Format (XLIFF) 650 XML SQL Utility (XSU) 647 XML-Fragment 618 XMLType 25 Analysemethoden 612 appendChild()-Anweisung 612 Bearbeitungsmethoden 612 createxml()-Anweisung 612 deleteXml()-Anweisung 612

1452.book Seite 881 Donnerstag, 5. August 2010 3:55 15

Index

existsNode()-Anweisung 612 extract()-Anweisung 612, 631, 634, 637 extract-Anweisung 609 extractValue()-Anweisung 612, 631 insertXmlBefore()-Anweisung 612 isFragment()-Anweisung 612 isSchemaValid()-Anweisung 612 isSchemaValidated()-Anweisung 612 Konstruktorfunktion 611 Methoden 611 text()-Anweisung 637 transform()-Anweisung 612 Verwendung von XMLType als Spaltentyp 606 XSD 25 XSLT 25, 241

Z Zeichensatzkodierung 37, 120 ASCII 121 ISO-8859 121 Multi-Byte-Zeichensatz 120 Single-Byte-Zeichensatz 120 Unicode 122 UTF 122 UTF-8 613 Zeichensatzkodierung bei Oracle 122 Nationale Zeichensatzkodierung 124 NLS 124 Zeitstempel 154 Zugriff auf Daten über PL/SQL-Packages 743

881