Sie sind auf Seite 1von 503

Heinz-Gerd Raymans

Oracle-Programmierung
Datenbankprogrammierung und -administration

Bitte beachten Sie: Der originalen Printversion liegt eine CD-ROM bei. In der vorliegenden elektronischen Version ist die Lieferung einer CD-ROM nicht enthalten. Alle Hinweise und alle Verweise auf die CD-ROM sind ungltig.

ADDISON-WESLEY
An imprint of Pearson Education
Mnchen Boston San Francisco Harlow, England Don Mills, Ontario Sydney Mexico City Madrid Amsterdam

Die Deutsche Bibliothek CIP-Einheitsaufnahme Ein Titeldatensatz fr diese Publikation ist bei Der Deutschen Bibliothek erhltlich Die Informationen in diesem Produkt werden ohne Rcksicht auf einen eventuellen Patentschutz verffentlicht. Warennamen werden ohne Gewhrleistung der freien Verwendbarkeit benutzt. Bei der Zusammenstellung von Texten und Abbildungen wurde mit grter Sorgfalt vorgegangen. Trotzdem knnen Fehler nicht vollstndig ausgeschlossen werden. Verlag, Herausgeber und Autoren knnen fr fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung bernehmen. Fr Verbesserungsvorschlge und Hinweise auf Fehler sind Verlag und Herausgeber dankbar. Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten ist nicht zulssig. Fast alle Hardware- und Softwarebezeichnungen, die in diesem Buch erwhnt werden, sind gleichzeitig auch eingetragene Warenzeichen oder sollten als solche betrachtet werden. Umwelthinweis: Dieses Produkt wurde auf chlorfrei gebleichtem Papier gedruckt. Die Einschrumpffolie zum Schutz vor Verschmutzung ist aus umweltvertrglichem und recyclingfhigem PE-Material.

10 9 8 7 6 5 4 3 2 1 04 03 02 01 ISBN 3-8273-1733-9 2001 by Addison-Wesley Verlag Ein Imprint der Pearson Education Deutschland GmbH Martin-Kollar-Strae 1012, D-81829 Mnchen/Germany Alle Rechte vorbehalten Einbandgestaltung: Lektorat: Herstellung: Korrektorat: Satz: Druck und Verarbeitung: Printed in Germany Hommer Design, Haar bei Mnchen Martin Asbach, masbach@pearson.de Elisabeth Egger, eegger@pearson.de Christine Depta, Freising mediaService, Siegen Bercker, Kevelaer

Inhaltsverzeichnis
Vorwort .................................................................................................... 9 V.1 Zum Inhalt ...............................................................................................10 1 Oracle erste Schritte ............................................................................ 13 1.1 Grundlagen..............................................................................................13 1.1.1 Klienten und Diener..................................................................14 1.1.2 Aufbau des Oracle-DBMS..........................................................18 1.1.3 Aufbau einer Oracle-Datenbank ................................................20 1.2 Installation ...............................................................................................24 1.2.1 Der Installationsvorgang ...........................................................25 1.2.2 Installation der Version 8 ..........................................................26 1.2.3 Installation von 8i .....................................................................32 1.3 Dienste unter Windows-NT ......................................................................35 1.4 Verbindung zur Datenbank herstellen ......................................................37 1.4.1 Einfhrung in SQL*Net bzw. Net8 ............................................38 1.4.2 Verbindung zur Starterdatenbank herstellen..........................40 1.4.3 Konfiguration mit Hilfe von Net8 Easy Config ...........................48 1.4.4 Oracle-Networking mit Hilfe des Net8 Assistant ........................53 1.4.5 Ausblick ....................................................................................60 1.5 Erstellen einer Datenbank .........................................................................62 1.5.1 Struktur einer Oracle-Datenbank...............................................62 1.5.2 Das manuelle Verfahren ............................................................65 1.5.3 Der Oracle Database Assistant ..................................................72 1.5.4 Automatische Generierung unter NT ........................................86 1.6 Administrierung der Datenbanken............................................................87 1.6.1 Instanz starten und stoppen .....................................................88 1.6.2 Datenbank ffnen und schlieen ..............................................89 1.6.3 Lschen einer Datenbank .........................................................91 1.7 Der Oracle Storage Manager ....................................................................92 1.8 SQL*Plus ..................................................................................................95 1.8.1 Abfragen eingeben und ausfhren............................................97 1.8.2 SQL*Plus als Skriptinterpreter..................................................100 1.9 Das SQL-Worksheet................................................................................105 Datenbankobjekte in einer Oracle-DB ...................................................109 2.1 Der Oracle-Schema-Manager .................................................................109 2.2 Beschreibung der Objekte ......................................................................113 2.2.1 Array-Typ (Array Types) ..........................................................114 2.2.2 Cluster (Clusters) ....................................................................119

Inhaltsverzeichnis

2.3

2.4

2.2.3 Datenbank-Link (Database Links) ............................................120 2.2.4 Funktion (Functions)...............................................................123 2.2.5 Index (Indexes).......................................................................127 2.2.6 Objekttyp (Object Types) .......................................................132 2.2.7 Paketrumpf (Package bodies)..................................................137 2.2.8 Paket (Packages) .....................................................................138 2.2.9 Prozedur (Procedures) ............................................................149 2.2.10 Warteschlangentabelle (Queue Tables) ...................................151 2.2.11 Abgleichengruppe (Refresh groups)........................................156 2.2.12 Sequenz (Sequences)..............................................................156 2.2.13 Log Materialisierte View (Snapshot logs).................................160 2.2.14 Materialisierte View (Snapshots) .............................................160 2.2.15 Synonym (Synonyms).............................................................170 2.2.16 Tabellentyp (Table Types).......................................................172 2.2.17 Tabelle (Tables) ......................................................................185 2.2.18 Trigger (Triggers) ...................................................................203 2.2.19 Ansicht (Views) .......................................................................212 2.2.20 Zusammenfassung..................................................................216 Die Beispieldatenbank anlegen ...............................................................218 2.3.1 Anlage des Schema-Eigners ....................................................219 2.3.2 Verwalten der Tablespaces......................................................222 2.3.3 Anlegen des Schemas .............................................................223 Datenmigration......................................................................................230 2.4.1 Variationsmglichkeiten..........................................................230 2.4.2 Laden unserer Beispiel-DB.......................................................233 2.4.3 Der Data Manager..................................................................236 2.4.4 Laden der Stammdaten per SQL*Loader .................................239 2.4.5 Wie geht es weiter? ................................................................247

Abfragen ...............................................................................................249 3.1 Einfache Auswahlabfragen......................................................................249 3.1.1 Struktur einer Auswahlabfrage ................................................250 3.1.2 Where-Bedingungen...............................................................254 3.1.3 Ergebnisse sortieren ................................................................259 3.1.4 Gruppierungen.......................................................................261 3.1.5 Spalten vertexten ...................................................................265 3.2 Verknpfungen ......................................................................................266 3.2.1 Inner-Joins ..............................................................................268 3.2.2 Unterabfragen ........................................................................271 3.2.3 Outer-Joins .............................................................................278 3.2.4 Mengenoperationen ...............................................................281 3.2.5 Hierarchische Abfragen...........................................................287

Inhaltsverzeichnis

3.3

3.4

3.5

nderungsabfragen................................................................................298 3.3.1 ndern von Daten ..................................................................298 3.3.2 Lschen von Daten .................................................................301 3.3.3 Einfgen von Daten ................................................................303 3.3.4 Sperren von Datenstzen ........................................................306 3.3.5 Erstellen eines nderungscursors ............................................309 3.3.6 Transaktionen .........................................................................319 Tuning von Abfragen .............................................................................324 3.4.1 Abfrageoptimierung ...............................................................325 3.4.2 Ausfhrungsplne...................................................................329 3.4.3 Ein paar Grundregeln fr die Erstellung von Abfragen.............336 3.4.4 Verwenden von Hints .............................................................341 Data Dictionary Views ............................................................................346 3.5.1 Analyse der Datenbankobjekte................................................347 3.5.2 Aktivitten in der Datenbank abfragen....................................352 3.5.3 Zugriffsrechte entschlsseln ....................................................355

Benutzer und Rollen ..............................................................................357 4.1 Einfhrung in die Benutzerverwaltung....................................................357 4.1.1 Das Rollenkonzept ..................................................................359 4.1.2 Der Oracle Security Manager ..................................................359 4.2 Benutzerverwaltung mit SQL..................................................................361 4.2.1 Einen Benutzer bearbeiten ......................................................361 4.2.2 Rollen anlegen und bearbeiten ...............................................363 4.2.3 Profile anlegen und bearbeiten ...............................................363 4.3 Rechtevergabe mit SQL ..........................................................................366 4.3.1 Vergabe von Einzelrechten und Rollen ....................................366 4.3.2 Zugriffsschutz auf Datensatzebene..........................................370 4.3.3 Benutzerverwaltung in der Praxis ............................................375 4.4 Auswertung der Benutzerprofile .............................................................375 PL/SQL-Programmierung ......................................................................381 5.1 Einfhrung in PL/SQL .............................................................................381 5.1.1 Allgemeines ............................................................................381 5.1.2 Blockstruktur ..........................................................................384 5.1.3 Datentypen ............................................................................386 5.1.4 Funktionen .............................................................................398 5.1.5 Ausgabe von Meldungen........................................................410 5.1.6 Konditionalbedingungen ........................................................412 5.1.7 Schleifen.................................................................................415 5.1.8 Datenbankabfragen ................................................................418 5.1.9 Fehlerbehandlung ..................................................................429 5.1.10 Dateiverarbeitung...................................................................441 5.1.11 Pipes.......................................................................................446 5.1.12 Verwenden von PL/SQL ..........................................................451

Inhaltsverzeichnis

5.2

Anwendungsbeispiele.............................................................................454 5.2.1 Benutzerverwaltung................................................................454 5.2.2 nderungsprotokollierung ......................................................460 5.2.3 Komplexe Integrittsbedingungen..........................................465 5.2.4 Exporthilfe ..............................................................................475

Anwendungsentwicklung ......................................................................481 6.1 Grundlagen............................................................................................481 6.1.1 ODBC-Verbindung .................................................................482 6.1.2 Verwenden der Oracle-Objekte...............................................491 Stichwortverzeichnis .............................................................................495

Vorwort
Noch ein Buch ber Oracle?! Nun, in einem haben Sie sicher Recht: Bcher ber Oracle gibt es sicherlich eine ganze Menge. Aber als ich im Sommer 1998 intensiveren Kontakt zu diesem Datenbanksystem bekam, htte ich mir ein solches Buch gewnscht. Ich habe es gesucht, aber nicht gefunden das ist einer der Grnde, warum ich es hier schreibe. Als ich als freiberuflicher Berater im Rahmen eines PeopleSoft-Projekts engen Kontakt zu Oracle bekam, da hatte ich neben umfangreicher Programmiererfahrung und detaillierten SQL-Kenntnissen auch weitreichende Erfahrungen mit verschiedenen Datenbanksystemen, beispielsweise Sybase oder dem Microsoft SQL-Server. Wenn Sie auf mein oben genanntes Datum geachtet haben und sich ein wenig auskennen, dann werden Sie jetzt sagen damals waren die beiden Server doch nahezu gleich. Stimmt genau, und damit sind wir der eingangs genannten Fragestellung wieder ein Stckchen nher gekommen. Beim Umgang mit Oracle war nmlich vieles anders, als bei den bisherigen DBMSSystemen. Die Werkzeuge sind andere, die Struktur der Datenbank (Schema, Tablespace) ist anders, Abfragen mssen zum Teil anders gestaltet werden. Anders ausgedrckt: Es gibt andere Restriktionen, aber auch andere Mglichkeiten. Diese auf einem Blick zu erkennen und umzusetzen ist nicht ganz einfach, und genau hier soll dieses Buch helfen. Was hat man denn fr Mglichkeiten, wenn man im Rahmen eines Projekts auf eine Datenbank stt, mit der man sich bisher noch gar nicht oder zumindest nicht regelmig bzw. nicht so oft beschftigt hat? Jedes Mal einen Kurs besuchen? Wohl dem, der diese Mglichkeiten hat. Das Handbuch lesen? Ich wnsche Ihnen bei Oracle viel Spa dabei und glauben Sie mir: Die Bibel knnen Sie leichter lesen; auerdem ist sie auch noch weniger umfangreich. Die einzige Variante ist, sich mal wieder mglichst schnell per Try and Error einzuarbeiten. Ein bisschen Hilfe kann hierbei aber nicht schaden, und genau diese halten Sie gerade in Ihren Hnden. Ich betrachte eine Datenbank immer als Werkzeug, als Mittel zum Zweck, mehr oder weniger Datenstze irgendwo zu speichern und bei Bedarf auch wiederzufinden. Genau wie das komplexe Thema Netzwerk, gehe ich in meinen Projekten immer davon aus, dass diese Dinge funktionieren und sich kompetente Kollegen um die Details kmmern. Ich bin eher fr die Lsung irgendwelcher Anwenderprobleme zustndig. Ich wei, was man mit einer Bohrmaschine alles machen kann, aber muss ich deshalb auch wissen, aus wie vielen Teilen meine Bohrmaschine besteht, wie man sie in alle Einzelteile zerlegen und wieder zusammensetzen kann? Ich denke nicht, Stecker rein muss reichen; danach kann ich ein schnes Loch bohren.

10

Vorwort

Genau aus diesem Blickwinkel ist dieses Buch aufgebaut. Bestimmte Themen, fr die es in der Praxis Datenbankadministratoren und Netzwerkbetreuer gibt, werden ganz bewusst nur grob skizziert oder sogar ganz weggelassen. Gleiches gilt fr Funktionen, die in der Praxis nur selten vorkommen und fr die Sie, wenn Sie die Grundzge von Oracle erst einmal beherrschen, schnell Informationen in den Handbchern finden. Dieser Workshop kooperiert also mit der Dokumentation des Herstellers, er versteht sich also nicht als Ersatz, sondern lediglich als Ergnzung der ziemlich umfangreichen Online-Handbcher. Er soll Ihnen helfen, sich in die wichtigsten Themen schnell und mit Hilfe pragmatischer Beispiele einzuarbeiten. Abschlieend mchte ich in diesem Vorwort natrlich alle erwhnen, die mich zu diesem Buch inspiriert oder bei der Erstellung untersttzt haben. Da sind zunchst einmal die netten Kollegen des letzten Deutschen Bank-Projekts: warum soll ich nicht mal all das aufschreiben, was ich in den letzten dreiig Monaten erzhlt habe. Dem letzten Projekt, der Einfhrung von PeopleSoft, kommt natrlich insgesamt eine tragende Rolle zu, denn es lieferte einige der in diesem Buch aufgearbeiteten Anregungen und Beispiele. Erwhnen mchte ich auch meine beiden Kinder: euch traf es mal wieder am meisten, als Papa in den letzten Wochen noch weniger Zeit als sonst hatte. Ich wnsche Ihnen nun viel Spa und Erfolg beim Lesen und Durcharbeiten dieses Buches. Ihr Heinz-Gerd Raymans

V.1

Zum Inhalt

Bevor ich etwas zum Inhalt sage, mchte ich noch vorwegnehmen, dass alle Beispiele und Erklrungen zunchst mit einer 8er-Version und zum Abschluss noch einmal mit der Version Oracle8i Release 2 (Version 8.1.6) berprft wurden. Aus diesem Grund wurden im Nachhinein noch verschiedene Passagen erweitert, so dass Sie mit diesem Buch auch ein Vergleichswerk fr die beiden zur Zeit noch auf dem Markt befindlichen Versionen besitzen. Auf der anderen Seite sind viele der hier angesprochenen Themen relativ versionsstabil und gelten vielleicht abgesehen von den Bildern und einigen Programmnamen fr alle 8er-Versionen bzw. in Teilen sogar fr eine Datenbank der Version 7. Das Buch hat also vornehmlich das klassische Datenbankgeschft in Form von SQL, Views, Triggern usw. im Auge und berlsst die neuen 8i-Erweiterungen wie Internet-Integration, JDeveloper und Java anderen Werken, die sich schwerpunktmig mit diesen Themen beschftigen (z.B. Oracle 8i und Java, ADDISON-WESLEY, ISBN 3-8273-1485-2). Im ersten Teil des Workshops Oracle erste Schritte geht es neben einigen allgemeinen Grundlagen vor allem um die Installation von Oracle, beispielsweise auf einem NT-Client (z.B. Notebook) oder Server mit anschlieender Erstellung einer eigenen Datenbank und deren Einbindung in das Oracle-Netzwerk (Net8). Sowohl

Zum Inhalt

11

bei der Erstellung der Datenbank, als auch bei deren Einbindung in das Netzwerk werden Sie verschiedene Methoden kennen lernen, um diese Aufgaben manuell oder mit Hilfe des einen oder anderen Werkzeugs zu erledigen. Mit Hilfe des zweiten Hauptkapitels erhalten Sie einen berblick ber die in Oracle verfgbaren Datenbankobjekte. Zunchst werden die einzelnen Objekte aufgezhlt bzw. kurz beschrieben und im weiteren Verlauf wird die im Kapitel 1 erstellte Datenbank mit Leben gefllt, d.h. die blicherweise bentigten Tabellen und Indices werden angelegt. Abschlieend wird die Datenbank mit Hilfe der auf der CD befindlichen Daten gefllt. Auch hierzu lernen Sie verschiedene Methoden, vor allem auch mehrere Varianten zur Verwendung des Oracle-Import-Managers kennen. Der nchste bzw. dritte Teil des Buches widmet sich dem komplexen Thema Abfragen. Ausgehend von einfachen Auswahlabfragen geht der Streifzug weiter durch die Welt der Verknpfungen (Joins) und mndet danach in den Komplex der nderungsabfragen inklusive dem Erstellen von Cursorn zur Durchfhrung von Datenbanknderungen. Abgerundet wird der ganze Themenkomplex mit einigen Ausfhrungen und Tipps zum Thema Abfragetuning und verschiedenen Beispielen zur Anwendung der verfgbaren Data-Dictionary-Views, mit deren Hilfe Sie das Oracle-System bzw. Ihre Datenbank analysieren knnen. Dem Thema Benutzter- und Rollenprofile widmet sich der vierte Teil des Buches. Hier lernen Sie die wichtigsten Ausprgungen dieser Profile mitsamt verschiedener Verfahrensweisen zu deren Verwaltung kennen. Im fnften Buchteil finden Sie eine Einfhrung in die PL/SQL-Programmierung. Gleichgltig ob es immer gleich um die Programmierung von Prozeduren oder Funktionen oder nur um die Erstellung grerer Skripts oder komplexerer nderungscursors geht: mit PL/SQL haben Sie eine schier unerschpflichen Menge von Mglichkeiten. Abgeschlossen wird das Kapitel mit verschiedenen Anwendungsbeispielen, beispielsweise einer universellen Exportfunktion. Der letzte Teil des Buches nhert sich noch einmal der Anwendungsentwicklung. Neben ein paar allgemeinen Hinweisen finden Sie hier auch Beispiele wie Sie mit Hilfe von ODBC oder den Oracle Objects im Handumdrehen leistungsfhige FrontEnd-Anwendungen erstellen knnen. Als Demonstrationsobjekt finden Sie unter anderem eine Funktion, mit deren Hilfe Sie von Excel aus Abfragen in der OracleDatenbank starten knnen. Nun folgt zum Abschluss noch ein Hinweis in eigener Sache. Die meisten Dinge im Leben sind nicht perfekt, das gilt vielleicht auch fr den einen oder anderen Satz oder Erklrung in diesem Buch. Bedenken Sie, dass wenn man solche Bcher neben seiner normalen Arbeit schreibt, der letzte Eintrag im Windows-Ereignisprotokoll hufig knapp vor oder weit hinter 0:00 liegt. Vielleicht gibt es aber auch ein Thema, das eigentlich gut in dieses Buchkonzept passt, zur Zeit aber berhaupt nicht behandelt wird. Was ich eigentlich sagen will ist, dass gute Ideen, konstruktive Kritik, interessante Beispiele aber auch Lob immer willkommen sind und wenn Sie wollen, dann knnen Sie mir Ihre Anregungen und Bemerkungen direkt an die Adresse heinz-gerd.raymans@raymans-consulting.de zusenden, doch nun wnsche ich Ihnen erst einmal viel Spa bei der Arbeit.

Oracle erste Schritte

Ich finde, dass auch ein technisches Buch einen Spannungsbogen haben sollte. In diesem Buch beginnt er im Kapitel Grundlagen mit der Erluterung verschiedener Konzepte und Grundbegriffe. Sofern Sie schon einmal mit hnlichen Datenbanksystemen (z.B. Sybase, Informix oder dem MS SQL-Server) gearbeitet haben, dann knnen Sie das Grundlagen-Kapitel natrlich auch getrost bergehen; Sie werden dort nichts Neues mehr erfahren. Danach beschftigen wir uns ein wenig mit der Installation einer Oracle-Datenbank, inklusive dem Einrichten des Zugriffs ber SQL*Net. Hiernach folgen die Erstellung verschiedener Tabellen und das Laden von Musterdaten, die im weiteren Verlauf des Buches fr Beispiele und bungen immer wieder bentigt werden. Im Rahmen dieser Einfhrung werden Sie also auch erste Erfahrungen mit Oracle sammeln knnen und wichtige Werkzeuge (z.B. SQL-Worksheet, Loader oder SQL*Plus) kennen lernen.

1.1

Grundlagen

Was ist eine Datenbank, was ein Datenbank-Management-System? Wie ist der schematische Aufbau einer Oracle-Datenbank? Was ist EDV? Nein, die letzte Frage werde ich hier nicht behandeln, aber zu den anderen beiden Fragen will ich schon das eine oder andere anmerken. Die Antwort auf die erste Frage scheint komplex, jedoch ist die Antwort darauf kurz, prgnant und ziemlich einfach. Eine Datenbank ist eine strukturierte Sammlung von Daten das war schon alles! Um mit diesen Daten bzw. der Datenbank arbeiten zu knnen, bentigen wir blicherweise noch geeignete Software, wobei man hierbei von einem Datenbank-Management-System (oft und auch hier mit DBMS abgekrzt) spricht, wenn sie vor allem das anwendungsunabhngige Arbeiten mit einer oder mehreren Datenbanken ermglicht. Strukturierte Datensammlungen gab es eigentlich schon immer. Aber, und das wissen vor allem diejenigen, die schon lnger im EDV-Geschft ttig sind, der Umgang mit gespeicherten Daten war nicht immer so komfortabel wie heute, denn oftmals musste man sich unter anderem auch um Verfahrensweisen zum Einfgen oder Lschen von Datenstzen oder dem schnellen Wiederfinden von Informationen kmmern. Ein Ergebnis dieser Verfahrensweisen war meistens eine sehr enge Verzahnung von Anwendungsprogramm und Datenbasis. Bei einem DatenbankManagement-System werden solche Detailarbeiten wie das Einfgen, Lschen oder Finden von Daten von ihm selbst erledigt. Hierzu erhlt es vom Anwendungsprogramm lediglich bestimmte Kommandos in Form einer speziellen Sprache. Durch das vorhandene Regelwerk dieser Sprache und der Mglichkeit, das viele verschiedene Anwendungsprogramme die zugehrigen Kommandos absetzen knnen, entsteht die gewnschte Anwendungsunabhngigkeit.

14

Oracle erste Schritte

1.1.1

Klienten und Diener

Entsprechend der eben erluterten Definition handelt es sich auch bei dem Produkt Access von Microsoft also wirklich um ein Datenbank-Management-System. Zum einen ermglicht es die strukturierte Speicherung von Datensammlungen und zum anderen besteht fr viele Anwendungen (nicht nur Access selbst) die Mglichkeit, mit den Daten der Access-Datenbank zu arbeiten. Dennoch gibt es aber einen gravierenden Unterschied zwischen beispielsweise Access und einem Oracle-DBMS. Technisch aber trotzdem vereinfachend betrachtet besteht das DBMS von Access aus einer unendlichen Anzahl von DLLs (Dynamic Link Libraries = Dynamische Laufzeitbibliothek), die bei Bedarf in den Speicher Ihres Rechners geladen werden. Diese DLLs dienen dazu, die bentigten Datenbankkommandos entgegenzunehmen, zu interpretieren und in der Datenbank entsprechend auszufhren. Bei der Datenbank handelt es sich meistens um eine (MDB-) Datei, die sofern man nicht alleiniger Nutzer ist, auf einem zentralen Dateiserver abgelegt ist. Betrachten Sie hierzu die zugehrige Abbildung (vgl. Abb. 1.1).

Arbeitsplatz Win NT, 95, 98, 2000


Excel Access

Server

Access-DBMS Netzwerk Datenbank

Abbildung 1.1: Struktur eines arbeitsplatzorientierten DBMS-Systems

Gem der Abbildung 1.1 wird eine auf einem Dateiserver gespeicherte Datenbank von Ihrem Arbeitsplatz aus mit Hilfe des Access-DBMS ber das Netzwerk abgefragt. Dabei liegen alle an diesem Prozess wesentlich beteiligten Komponenten, also die beteiligten Anwendungen (Excel, Access oder andere) und das DBMS (in unserem Beispiel die entsprechenden DLLs), im Speicher des Arbeitsplatzrechners. Das DBMS ruft die bentigten Daten aus der Datenbank ab bzw. fhrt dort nderungen durch. Mit ein wenig Phantasie sollte klar werden, was bei einer solchen Architektur alles passieren kann:

Die Anzahl der Anwender entspricht der Anzahl der im Einsatz befindlichen DBMS-Systeme. Ein solches DBMS-System ist eigentlich immer ein hchst komplexes Gebilde mit einer Unzahl verschiedenster Funktionalitten. Es sollte somit plausibel sein, dass seine Arbeitsgeschwindigkeit nicht unwesentlich von

Grundlagen

15

den Ressourcen des ausfhrenden Rechners abhngt. Muss also die Leistungsfhigkeit des DBMS-Systems gesteigert werden, so mssen unter Umstnden alle Rechner auf denen es luft aufgerstet werden. Bestimmte Sachverhalte werden besonders deutlich, wenn man ein wenig schwarz malt bzw. drastisch bertreibt. Stellen wir uns einfach mal vor, unsere Datenbank htte eine Gre von mehreren hundert Megabyte. Mit Hilfe einer Abfrage suchen wir eine winzige Information, z.B. einen Namen, wobei die Form der gewhlten Abfrage vielleicht dazu fhrt, dass sie vom DBMS nicht optimal ausgefhrt werden kann und somit zur Bereitstellung unseres gesuchten Namens alle Datenstze der Datenbank abgerufen werden mssen. In dem Fall mssten alle Datenstze der Datenbank ber das Netzwerk zu unserem Arbeitsplatzrechner transportiert werden, damit das DBMS uns anschlieend als Ergebnis einen oder noch besser keinen Namen prsentiert. Ein Phnomen, dass es in der Praxis wirklich gibt. Eine Abfrage fhrt zu einer erheblichen Belastung des Netzwerks und unseres Rechners und am Ende kommt wenig oder sogar nichts heraus. Sie wollen ein Feld einer in der Datenbank gespeicherten Tabelle ndern, und zwar fr jede vorhandene Reihe. Auch in diesem Fall muss das auf Ihrem Rechner laufende DBMS jeden Satz ber das Netzwerk anfordern, die nderung durchfhren und anschlieend fr die Rckbertragung und die Speicherung des neuen Wertes sorgen.

Damit keine Missverstndnisse entstehen: ich will das Produkt Access hier nicht kritisieren oder schlecht machen. MS-Access ist lediglich ein - wenn auch ziemlich bekannter - Vertreter fr diese Gruppe von DBMS-Systemen. An dem Beispiel sollte lediglich verdeutlicht werden, wie diese Klasse von Datenbank-Management-Systemen (z.B. auch FoxPro, Paradox, Approach u.a.) funktionieren. In der englischsprachigen Literatur wird ein solches DBMS oftmals auch als File Sharing Database System bezeichnet. Die Bezeichnung kommt daher, dass sich hierbei in der Tat alle Anwendungen die auf dem Server befindliche Datenbank direkt teilen; jede Anwendung veranlasst beispielsweise indirekt ber das DBMS das ffnen der zugehrigen Datenbankdateien. Was muss man nun ndern, um die eben genannten Eigenschaften zu verndern bzw. zu verbessern? Zunchst einmal wre wnschenswert, das Datenbanksystem nher an seine Datenbank zu bringen, um Lese- oder nderungsanforderungen einfacher und schneller bearbeiten zu knnen. Mit anderen Worten: das DBMS muss auf den Server umziehen, wo auch die Datenbank gespeichert ist. Betrachten Sie einmal die Abbildung 1.2. Durch den Umzug des DBMS ist ein System entstanden, wie Sie es in der heutigen Praxis oftmals vorfinden. Zum einen haben Sie den Arbeitsplatzrechner, den Client, auf dem die eigentlichen Anwendungen laufen. Diese fordern mit Hilfe von Nachrichten Daten aus der Datenbank ab oder veranlassen dortige nderungen. Die Nachrichten werden ber das Netzwerk an das auf dem Server laufende DBMS bermittelt. Das sorgt fr die Bereitstellung der gewnschten Daten und veranlasst die bermittlung der Ergebnisse an den Client und im Falle von nderungen werden berhaupt keine Daten mehr ber das Netzwerk transportiert.

16

Oracle erste Schritte

Arbeitsplatz Win NT, 95, 98, 2000


Excel Access

Server
DBMS
Nachrichtendienst

Nachrichtendienst Netzwerk

Datenbank

Abbildung 1.2: DBMS mit einer Client/Server-Struktur

Oftmals kommunizieren die Clients nicht einmal direkt mit dem DBMS, sondern das leistet sich fr diese besondere Aufgabe einen vorgelagerten Prozess, quasi so eine Art Sekretariat. Solche Prozesse werden blicherweise als Listener bezeichnet, und wie man der englischen Bezeichnung ableiten kann, besteht seine Hauptaufgabe darin, das Netzwerk permanent nach Nachrichten fr sein zugehriges DBMS abzuhren. brigens, genau wie im richtigen Leben, wo ein Sekretariat durchaus fr mehrere Chefs arbeiten kann, kann auch solch ein Listener Nachrichten fr mehrere installierte DBMS-Instanzen abhren bzw. weiterleiten. Ein weiterer Unterschied zu den File Sharing Database Systemen ist, dass das auf dem Server befindliche DBMS die zugehrigen Datenbankdateien blicherweise exklusiv nutzt. Die einzelnen Anwendungen verbinden sich lediglich direkt oder ber den Listener mit dem DBMS; auch bei tausend Anwendern sind die Datenbankdateien nur einmal geffnet. Sie haben nun auf ziemlich pragmatische Weise die Struktur eines Client/ServerSystems (CS-System) kennen gelernt. Ich mchte die wesentlichen Eigenschaften in der folgenden Tabelle noch einmal zusammenfassen:
File Sharing System Das DBMS befindet sich auf dem Client. Soll in einer Datenbank jeder Datensatz aktualisiert werden, so mssen alle Datenstze zum Client transportiert werden. Dort werden die nderungen durchgefhrt und anschlieend mssen alle Datenstze wieder in die Datenbank auf den Server zurckgeschrieben werden. Client/Server System Das DBMS befindet sich auf dem Server. Der Client schickt eine entsprechende Aktualisierungsnachricht an das DBMS. Dieses fhrt anschlieend direkt die notwendigen Aktualisierungen in der Datenbank durch.

Grundlagen

17

File Sharing System In vielen Anwendungen hngt die Arbeitsgeschwindigkeit direkt von der Geschwindigkeit des DBMS ab. Daher muss jeder Arbeitsplatzrechner entsprechend leistungsfhig sein, damit das auf ihm laufende DBMS ber gengend Ressourcen verfgen kann. Wird die konkrete Anwendung zu langsam und liegt dies zum Beispiel an der Gre der Datenbank, so muss das DBMS und damit alle Arbeitsplatzrechner aufgerstet werden.

Client/Server System Der Server muss entsprechend leistungsfhig ausgelegt werden, damit das dort laufende DBMS die Anforderungen der Clients schnell genug abarbeiten kann. Die auf den Arbeitsstationen verfgbaren Ressourcen spielen (gbe es nicht Windows) eigentlich keine Rolle mehr. In dem Fall muss lediglich der Server entsprechend aufgerstet werden.

Tabelle 1.1: Gegenberstellung File Sharing und Client/Server System

Vielleicht ist bei den bisherigen Erklrungen der Eindruck entstanden, dass die Client/Server-Technologie von Datenbanksystemen gepachtet ist. Dem ist natrlich nicht so, d.h. ein modernes leistungsfhiges DBMS ist nur ein Vertreter vieler anderer CS-Anwendungen. Ganz allgemein gilt bei dieser Technik eigentlich nur, dass bestimmte Teile der Anwendung auf dem Server und andere Teile auf den Clients verfgbar sind und das beide Teile in Form von Nachrichten miteinander kommunizieren und der Client die zentral auf dem Server bereitgestellten Dienste bzw. Anwendungsfunktionen nutzt. Zurck zu den Datenbanksystemen. Ohne vernnftiges Netzwerk funktionieren natrlich beide System nicht richtig. Da ntzt auch der dickste Server nichts, wenn die Nachrichten bzw. Ergebnisse zum bzw. vom DBMS nicht vernnftig transportiert werden und auch der Client mit neuestem Prozessor und hunderten Megabyte RAM dreht eine Warteschleife nach der anderen, wenn die aus der Datenbank angeforderten Daten aufgrund des langsamen Netzwerks nur trpfchenweise ankommen. Bei soviel offenkundiger Werbung fr Client/Server mchte ich hier dennoch einmal kurz auf die Bremse treten. Ich werde in meinem weiteren Berufsleben keine CS-Systeme mehr in Unternehmen einfhren, in denen die fr einen reibungslosen Betrieb notwendigen Strukturen fehlen. Hiermit meine ich vor allem vorhandenes KnowHow ber das vorhandene Netzwerk und die eingesetzten Server oder vor Ort verfgbares Personal, das zumindest bestimmte Grundkenntnisse (z.B. Datensicherung, Erweitern der Datenbank, Hoch- und Runterfahren des DBMS) ber das neue Datenbanksystem besitzt. Ich habe schon hufiger schlechte Erfahrungen damit gemacht, wenn im Rahmen irgendwelcher Softwareprojekte ein DBMS auf C/S-Basis eingefhrt bzw. durchgesetzt wurde, dieses aber in der Softwarelandschaft des Kunden einen Fremdkrper darstellte. Solche Projekte laufen am Anfang meistens sogar ziemlich gut. Die eigene EDV mischt sich kaum ein (weil keine Ahnung) und alle auftretenden Probleme knnen, weil man im Rahmen des Projekts sowieso oft oder permanent vor Ort ist, rasch erledigt werden. Treten dann im laufenden Betrieb die blichen Problemchen auf (Server macht Mucken und damit auch das DBMS; Sessions hngen usw.), dann kann die Stimmung schnell drehen, entweder weil man jetzt aufgrund eines anderen Projekts nicht bzw.

18

Oracle erste Schritte

schlecht verfgbar ist oder weil der Kunde irgendwann die Lust verliert, immer neue Wartungsrechnungen zu bezahlen. Ein solcher Kunde wre mit einer Anwendung, die ihre bentigten Daten mit Hilfe einer File Sharing Datenbank verwaltet, besser bedient, da diese im laufenden Betrieb meistens ohne spezielle Kenntnisse betreut werden kann (DBMS kaputt = Anwendung auf dem Client neu installieren; Datenbank kaputt = Files von der normalen Datensicherung zurckspielen); klingt einfach und ist es meistens auch. Wie im Leben, so gibt es auch in der EDV mittlerweile fr jede Aufgabe das richtige Handwerkszeug und um so merkwrdiger ist es allerdings, dass die Auswahlentscheidung noch immer so hufig aus einer Bierlaune heraus oder auf dem Tennisbzw. Golfplatz getroffen wird. Ich wrde diesen Entscheidungstrgern gerne mal im Privatleben zusehen, wie sie die Heftzwecke fr ein neues Kindergartenbild mit dem Vorschlaghammer in der Wand versenken, anstatt hierfr den kleinen und handlichen Bastelhammer zu benutzen. Aber schlielich machte der Vorschlaghammer im Geschft den stattlicheren Eindruck, hier bekommt man wirklich was fr sein Geld und daher muss er einfach das richtige Tool fr alle denkbaren Aufgabenstellungen sein.

1.1.2

Aufbau des Oracle-DBMS

Aufgrund des letzten Kapitels wissen Sie nun, dass Oracle zur Klasse der Client/Server-Datenbank-Management-Systeme (CS-DBMS) gehrt und obwohl sich dieses Buch primr nicht an Techniker richtet, soll im Folgenden der konkrete Aufbau des Oracle-DBMS ein wenig genauer betrachtet werden. Sollten Ihnen die hier bzw. auch im nchsten Kapitel gelieferten Informationen zu oberflchlich sein, dann empfehle ich Ihnen den Genuss eines speziellen Buches fr Oracle-Datenbankadministratoren oder Sie schmkern einfach mal ein wenig in den per HTML gelieferten Handbchern. Im Buch Oracle8 Server finden Sie beispielsweise allein schon in den Abschnitten Server Concepts oder Oracle Server Administrator's Guide eine schier unerschpfliche Informationsquelle. Beim 8i-Server finden Sie diese beiden Kapitel auch wieder, wenn Sie auf der Startseite den Link Oracle8i Server and Data Warehousing folgen. In allen Versionen finden Sie die Online-Dokumentation brigens im \DOC-Verzeichnis, das direkt unter dem Oracle-Homeverzeichnis angeordnet ist. Schaut man etwas genauer auf die Funktionsweise eines Oracle-DBMS so stellt man fest, dass es sich in der Architektur ein wenig von unserer bisherigen allgemeingltigen Definition und in diesem Punkt auch in der Tat von andern DBMS-Systemen unterscheidet. Wir, nein ich, hatte gesagt, dass es sich bei einem DBMS um ein Stck Software handelt, das ein anwendungsunabhngiges Arbeiten mit einer oder mehreren Datenbanken ermglicht. Microsofts SQL-Server arbeitet beispielsweise nach diesem Prinzip. Bei dieser Datenbank finden Sie auf Ihrem Rechner genau einen Prozess, reprsentiert durch das Programm SQLSERVR.EXE, knnen aber trotzdem mit allen definierten Datenbanken arbeiten.

Grundlagen

19

Im Unterschied hierzu arbeitet bei Oracle ein DBMS (z.B. ORACLE80.EXE unter NT) immer genau mit einer Datenbank zusammen, was natrlich nicht heit, dass Sie nicht mehrere Datenbanken auf einem Rechner betreiben knnen Sie mssen in dem Fall auch einfach nur entsprechend viele Kopien des DBMS im Speicher laufen haben. Das ist also genau so, als wrden Sie Excel mehrfach starten und mit jeder Programmkopie genau eine Tabelle laden, wohingegen die definitionskonforme Arbeitsweise des SQL-Servers dem einmaligen Starten von Excel entspricht, wobei anschlieend fr jede Tabelle ein Arbeitsfenster geffnet wird. Im Oracle-Sprachgebrauch wird eine solche DBMS-Kopie blicherweise mit dem Begriff einer Instanz belegt. Technisch betrachtet verbirgt sich hinter einer solchen Instanz die Menge aller bentigten Prozesse zuzglich einem Stckchen reserviertem Hauptspeicher, der fr alle diese Prozesse erreichbar ist. Dieser Hauptspeicherbereich wird als System Global Area (SGA) bezeichnet, die Instanz selbst wird durch einen System-Identifer (SID) gekennzeichnet (vgl. Abb 1.3).

SID=orcl SGA = System Global Area

Oracle-Systemprozesse DBWR SMON PMON LGWR CKPT

Abbildung 1.3: Schematischer Aufbau einer Oracle-Instanz mit den wichtigsten Hintergrundprozessen

Sofern es Sie interessiert, finden Sie in der folgenden Aufstellung eine grobe Beschreibung, welche Funktionen die einzelnen Systemprozesse erfllen:

DBWR (Database Writer) schreibt in der SGA modifizierte Datenblcke zurck in die Datenbank. SMON (System Monitor) berwacht die Wiederherstellung der Datenbank bei einem Neustart. Ferner registriert dieser Prozess freiwerdende Bereiche in der Datenbank und vereinfacht somit deren Wiederbelegung. LGWR (Log Writer) Schreibt die im Rahmen von Transaktionen anfallenden Protokollinformationen in die zugehrigen Plattenbereiche (Redo-Log-Eintrge).

: :

20

Oracle erste Schritte

: :

CKPT (Checkpoint) Generiert die sogenannten Checkpoints, zu denen modifizierte Datenblcke aus der SGA in die Datenbank zurckgeschrieben werden. PMON (Process Monitor) berwachung der Benutzerprozesse. Freigabe der Ressource von abgebrochenen Benutzerprozessen.

Die SGA selbst ist auch in mehrere unterschiedliche Speicherbereiche aufgeteilt. Diese Speicherbereiche werden whrend der Initialisierung der Instanz angelegt und knnen in der Gre zur Laufzeit nicht gendert werden. In der folgenden Aufstellung finden Sie eine kurze Beschreibung der wichtigsten Speicherbereiche:

Database Buffer Cache In diesem Speicherbereich werden die gerade bentigten Datenblcke vorgehalten. Da blicherweise nicht alle Daten gleichzeitig in diesen Puffer passen, findet ein permanenter Ein- und Auslagerungsprozess zwischen aktuell bentigten und lnger nicht mehr gebrauchten Daten statt. Hierbei werden die am lngsten ungenutzten Puffer aus diesem SGA-Bereich ausgelagert (LRU-Algorithmus, LRU = Least Recently Used). Zur Erinnerung: zum Wegschreiben von nderungen aus diesem Puffer war der Prozess DBWR zustndig. Redo Log Buffer Die whrend einer Transaktion anfallenden Protokollinformationen werden in diesem Puffer zwischengespeichert. Shared Pool SQL-Befehle jeglicher Art, Funktionen oder Prozeduren werden in diesem Pool zwischengelagert, wobei diese hier gelagerten Abfragen direkt ausfhrungsfhig sind, d.h. sie werden hier mitsamt ihren Ausfhrungsplnen gespeichert. hnlich wie beim Database Buffer Cache wird auch dieser Bereich nach dem LRUAlgorithmus verwaltet, d.h. hufig benutzte Abfragen oder Prozeduren stehen direkt zur Ausfhrung zur Verfgung.

: :

Mehr Informationen zu diesen und weiteren Prozessen einer Oracle-Instanz sowie weitergehende Informationen ber den Aufbau der SGA finden Sie in der OracleDokumentation im Buch Server Concepts im Kapitel Memory Structure and Processes. Um selbst Datenbanken anzulegen bzw. die dazu notwendigen Schritte besser zu verstehen, reicht allerdings ein grobes Gefhl ber den Aufbau einer Instanz vllig aus.

1.1.3

Aufbau einer Oracle-Datenbank

Nachdem Sie nun ein paar Grundkenntnisse ber den Aufbau des Oracle-DBMS besitzen, mchte ich Ihnen auch noch ein paar Grundlagen ber den Aufbau der Datenbank vermitteln, d.h. es geht jetzt darum mal nachzuschauen, wie sich die Datenbank auf der Festplatte ausbreitet.

Grundlagen

21

Jedes Datenbanksystem speichert seine Daten in ganz gewhnlichen Dateien (wie auch sonst), d.h. sptestens hier finden Sie eine wichtige Nahtstelle zum vorhanden Betriebssytem, denn beim Anlegen und Verwalten dieser Dateien muss sich natrlich auch das DBMS an die vorgegebenen Spielregeln des Betriebssystems halten. Konkret geht es hierbei beispielsweise um Namenskonventionen (Lnge von Pfad- und Dateinamen, Sonderzeichen) oder eventuell vorhandene Grenbeschrnkungen von einzelnen Dateien oder des definierten Filesystems (UNIX). Fr uns als Anwender bildet die gesamte Datenbank eine logische Einheit. Physikalisch kann das ganz anders aussehen und hngt konkret vom vorhandenen DBMS ab. Es gibt sowohl Datenbanksysteme, wo die gesamte Datenbank auch immer genau einer Datei entspricht, als auch Systeme, wo jede Tabelle automatisch in einer eigenen Datei gespeichert wird. Oracle liegt irgendwo zwischen diesen beiden Extremem, wobei der genaue Standort sehr stark von Ihrer Datenbankdefinition abhngt. Oracle speichert Ihre Anwendungsdaten in Form von Tabellen. Eine solche Tabelle bentigt hierzu natrlich Platz, der ihr vom Datenbanksystem in Form eines sogenannten Tablespace bereitgestellt wird. Dieser Tablespace wird physikalisch und jetzt wird es interessant durch eine oder auch mehrere Dateien gebildet (vgl. Abb. 1.4).

Logisches Modell

Datenbank

Tablespaces

Tablespace 1

Tablespace 2

Physische Dateien

Datei 1

Datei 2

Datei 3

Festplatten
Abbildung 1.4: Schematischer Aufbau einer Oracle-Datenbank

Betrachten Sie den schematischen Aufbau mit Hilfe der Abbildung 1.4. In dem Beispiel wird der Tablespace 2 durch zwei Dateien gebildet, die sogar auf unterschiedlichen Platten angelegt wurden. In diesen Tablespaces werden nun die bentigten Tabellen und anderen Datenbankobjekte (z.B. Indices) angelegt, d.h. es besteht beispielsweise die Mglichkeit, den fr eine Tabelle zustndigen Tablespace und damit vielleicht auch die Tabelle auf mehrere Platten zu verteilen, um hierdurch unter Umstnden bessere Zugriffsgeschwindigkeiten zu erreichen.

22

Oracle erste Schritte

Frher wurde viel mit diesen Optionen experimentiert, um das Antwortszeitverhalten des Systems und damit natrlich auch der Anwendung zu verbessern. Heute spielt bei diesen Mglichkeiten der Tuninggedanke eine immer geringere Rolle. Das liegt aus meiner Sicht vor allem an folgenden drei Grnden. Erstens hat man es heutzutage oftmals nicht mehr mit einzelnen direkt addressierbaren Platten, sondern ganzen Plattenstapeln (Disk-Arrays) zu tun. Hierdurch geht die direkte Kontrolle was genau wo gespeichert wird sowieso verloren bzw. das Speichermedium des Plattenstapels stellt schon von ganz alleine sicher, dass der Zugriff auf groe Dateien optimiert erfolgt. Zum zweiten bieten manche Betriebssysteme (z.B. UNIX) die Mglichkeit, die physikalische Plattenstruktur durch ein darber liegendes sogenanntes Filesystem zu verschleiern. Die zum Tablespace gehrenden Dateien werden dann in diesem Filesystem angelegt, also geht auch hierbei die direkte Kontrolle ber die Plattenzuordnung verloren. Der dritte und wesentlichste Grund ist aber, dass sich die Aufwnde dieser physikalischen Tuningmanahmen meistens nicht mehr rechnen. Zum einen ist die Hebelwirkung dieser Manahmen kleiner geworden. Die Rechner und Platten sind heutzutage so schnell, dass viele Anwendungen auch bei miserabelstem Speicherkonzept noch ordentlich laufen drften. Zum anderen zeigt sich der Engpassfaktor oft gar nicht mehr in der Form der durchgefhrten Datenzugriffe, sondern bertrieben verspielte grafische Oberflchen, hpfende Broklammern und hnliche Gimmiks. Die soeben aufgefhrten Grnde sollen Sie allerdings auch nicht zum anderen Extrem, nmlich Datenbanken mit nur einem Tablespace, verleiten. Die folgenden Regeln knnen Ihnen vielleicht bei der Strukturierung Ihrer Datenbank helfen, denn ein allgemeingltiges Patentrezept gibt es auch hier natrlich mal wieder nicht:

Viele Anwendungen definieren fr die bentigten Indexdateien einen separaten Tablespace. Wenn Sie nun noch versuchen, wenigstens diese zugehrigen Dateien in ein separates Filesystem bzw. auf anderen Platten zu verlagern, dann kann Ihr System getrennt auf Index- und Datenbereiche zugreifen. Selbst wenn dieser Eingriff Ihre Abfragen nur um 0,00x Sec beschleunigt; diese Manahme kostet nichts und es spricht auch ansonsten berhaupt nichts dagegen. Logische Gesichtspunkte knnen fr die Gestaltung der Tablespaces ausschlaggebend sein. Beispielsweise besteht die Anwendung aus mehreren verschiedenen Produkten (z.B. Finanzbuchhaltung, Personalabrechnung und Reisekosten), dann ist es sicherlich sinnvoll, die produktspezifischen Tabellen in eigens hierfr angelegte Tablespaces zu speichern. Dies erhht nicht nur die bersicht, sondern kann auch spezielle Wartungsarbeiten vereinfachen, denn die einzelnen Tablespaces knnen im laufenden Betrieb ein- oder ausgeschaltet werden. Auch wre die Entzerrung der Daten recht einfach, sollte eines der Produkte mal in eine eigene Datenbank umziehen mssen. Verteilen von Tabellen mit unterschiedlichem Wachstumsverhalten. Es kann durchaus sinnvoll sein, stark wachsende Tabellen von mehr oder weniger statischen Tabellen zu trennen. Es liegt irgendwie auf der Hand, dass der Verwal-

Grundlagen

23

tungsoverhead geringer sein muss, wenn eine stark wachsende Tabelle alleine in einem Tablespace liegt, als wenn sie zusammen mit anderen Tabellen um den noch freien Platz kmpfen muss. Anforderungen eines besonderen Betriebsablaufs knnen natrlich auch eine Rolle spielen. Wie ich schon erwhnte, besteht die Mglichkeit einen einzelnen Tablespace im laufenden Betrieb ein- bzw. auszuschalten. Solche Praktiken knnte man im Zusammenhang mit speziellen Programmen nutzen, die eine Tabelle im Batch komplett verndern, um diese Tabelle vor dem Programmlauf auf einfache und schnelle Weise zu sichern.

Innerhalb eines Tablespaces werden die Daten in sogenannten Segmenten gespeichert. Dabei bildet beispielsweise jede Tabelle oder jeder Index ein eigenes Segment. Die Segmente selbst bestehen aus einem oder mehreren zusammenhngenden Datenblcken (data block), wobei diese zusammenhngenden Blcke mit dem Begriff Extend bezeichnet werden. Ein solcher Datenblock ist die kleinste Speichereinheit, die Oracle beim Schreiben oder Lesen der Festplatte bewegt. Die Gre eines solchen Datenblocks knnen Sie beim Anlegen der Datenbank festlegen, indem Sie den Parameter DB_BLOCK_SIZE der Konfigurationsdatei entsprechend anpassen. Der Standardwert fr diese Gre ist betriebssystemabhngig und betrgt fr Windows-NT beispielsweise 2048 Byte.

Festplatte Segment 1. Extend 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb Tablespace 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb 2. Extend 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb 2Kb

Abbildung 1.5: Segmente, Extends und Datenblcke

Beim Anlegen eines Tablespace knnen Sie Regeln definieren, wie die einzelnen Segmente gebildet werden sollen, d.h. welche Gre beispielsweise die erste und jede weitere Ausdehnung (Extend) besitzen soll. Allerdings knnen Sie beim Anlegen der einzelnen Objekte diese Regel berschreiben und dem Objekt damit eine individuelle Speicherbelegungsregel mitgeben. Das bisher Gesagte soll an dieser Stelle ber den Aufbau einer Oracle-Datenbank zunchst einmal reichen. Mehr Informationen ber dieses spezielle Thema finden Sie weiter unten in diesem Buch im Kapitel 1.5 Erstellen einer Datenbank. Ansonsten mchte ich natrlich auch wieder auf die Oracle-Dokumentation verweisen. Hier finden Sie weiterfhrende Informationen zum Beispiel im Buch

24

Oracle erste Schritte

Oracle8. Folgen Sie dort dem Querverweis Server Concepts. Die Informationen finden Sie im Kapitel Database Structure and Space Management. In der 8i-Dokumentation finden Sie das Kapitel im Buch Oracle8i Concepts, das sich hinter dem Querverweis Oracle8i Server and Data Warehousing verbirgt.

1.2

Installation

Nun soll sich dieses Buch nicht an DBAs richten, und trotzdem finden Sie so ziemlich am Anfang ein Kapitel ber die Installation. Der Grund dafr ist ziemlich einfach: vielleicht haben Sie ja auch als klassischer Anwendungsentwickler oder Berater einmal Lust, ein Oracle-DBMS zu installieren, beispielsweise weil es auch auf Ihrem NT-Notebook prima luft. Sie haben richtig gelesen. Trotz der komplexen Struktur des Oracle-DBMS funktioniert es auch in primitiven Wohnstuben hchst zuverlssig. Ein gewhnlicher Rechner mit Windows-NT (Workstation) reicht vllig aus, um darauf eine lauffhige Installation durchzufhren. Vielleicht besteht ja im Rahmen des aktuellen Projekts die Mglichkeit, eine Version auf Ihrem Rechner zu installieren oder und das gilt natrlich vor allem fr alle selbstndigen Berufskollegen Sie kaufen sich gleich eine eigene Version. Die gibt es mittlerweile nmlich in einer Einplatzlizenz fr etwa 600_ zu kaufen, wofr Sie einen ca. zehn Zentimeter dicken CD-Stapel erhalten. Im brigen gibt es auch immer wieder mal spezielle Partnerprogramme, bei deren Teilnahme Sie ebenfalls die Mglichkeit haben, besonders gnstige Test- und Entwicklungslizenzen zu beziehen. Was den letzten Satz angeht, da haben sich die Zeiten wirklich sehr zum positiven gendert. Es ist noch nicht so lange her, da war es fr kleine Firmen, Einzelunternehmen oder Freiberufler schon ein bisschen schwieriger, ein Oracle-DBMS zu erwerben. Dabei war das gar nicht mal eine Frage des Preises, sondern eher so wie bei Ferrari. Da soll auch nicht jeder ein Auto kriegen, selbst wenn er es bezahlen kann. Heute ist das anders. Zum einen ist das Produkt in speziellen Konfigurationen sehr gnstig und zum anderen bemht man sich in den letzten Jahren seitens Oracle sehr, das Produkt durch spezielle Angebote auch kleinen Softwarehusern oder Freiberuflern schmackhaft zu machen. Immer noch geblieben ist der eine oder andere AHA-Effekt whrend oder nach der Installation; frei nach dem Motto Installation gelungen, Patient tot. Damit das bei Ihnen nicht passiert, will ich im Folgenden eine kleine Installationshilfe geben. Mit dem Begriff Installation habe ich eigentlich eine Reihe von Aktivitten gemeint. Zunchst einmal mssen Sie in der Tat die bentigte Software auf Ihren Rechner kopieren. Der nchste Schritt wre die Erstellung einer Datenbank und zum Schluss mssen Sie auch noch Kontakt zu Ihrer Datenbank herstellen.

Installation

25

1.2.1

Der Installationsvorgang

Die primre Installation der Software ist natrlich stark abhngig vom konkret eingesetzten Betriebssystem und der eingesetzten Oracle-Version. Im Prinzip geht es natrlich immer um das Gleiche: Sie mssen die bentigten Dateien von der Oracle-Produkt-CD auf Ihren Rechner kopieren. Prinzipiell muss man auch zwischen der Installation des Oracle-Servers und der bentigten Software fr die einzelnen Arbeitsstationen unterscheiden. Manchmal liegen diese beiden Produktpakete auch auf verschiedenen CDs vor (z.B. Oracle8 Server fr Sun SPARC und Oracle8 Client fr Windows 95 und NT). In den folgenden Abschnitten erhalten Sie sowohl Informationen zur Installation einer normalen 8er-Version als auch zum Installationsvorgang der 8i-Variante. Wie schon eingangs erwhnt, soll die Installation auf einem NT-Notebook erfolgen, d.h. Server und Client laufen auf dem gleichen Rechner. Die Installation erfolgt unter NT 4.0 (Workstation) mit Service Pack 5 auf einem DELL Latitude CPINotebook mit Pentium II-Prozessor (366 Mhz) und 256 MB Hauptspeicher. Keine Angst, Sie mssen jetzt nicht sofort aufrsten. Auf einem Rechner mit nur 64 MB Hauptspeicher und einem 166 Mhz-Prozessor luft der Oracle-Server auch ordentlich. Selbst mit noch weniger Ressourcen ist eine Installation mglich. Vor ein paar Jahren habe ich mal einen Oracle-Server (Version 7.3) auf einem Notebook mit nur 32 MB Hauptspeicher installiert, allerdings ging der Betrieb des Servers jetzt schon stark zu Lasten der Performance anderer Anwendungen. Das einzigste was einem beim ersten Hinschauen den Atem verschlgt ist der veranlagte Platzbedarf. Die aktuelle 8i-Version beansprucht in der Standardinstallation immerhin ca. 1 GB Plattenplatz (ohne Starter-Datenbank), wohingegen sich die normaler 8er-Version inklusive Starterdatenbank mit ein paar hundert MB freiem Platz installieren lsst. Ebenfalls phnomenal ist der temporre Platzbedarf des 8i-Installationsprogramms. Bei meinen Installationsversuchen lief das Programm erst dann bis zum Ende durch, nachdem auf meinem Systemlaufwerk ca. 100 MB fr Temporrdateien zur Verfgung standen. Unter Windows erfolgt die Installation von Oracle-Produkten mit Hilfe eines speziellen Setup-Programms, dem Oracle-Installer. Dieses Programm wird im brigen blicherweise auch selbst installiert, da Sie mit ihm jederzeit weitere Komponenten nachinstallieren oder auch berflssige Programmteile entfernen knnen. Sollte sich der Installer nach dem Einlegen der CD nicht automatisch melden, so starten Sie es einfach selbst, indem Sie das im Hauptverzeichnis der CD befindliche Programm SETUP.EXE ausfhren. Das Aussehen und die Funktionsweise des Installers war in den 7er und ersten 8er Versionen nahezu gleich. Erst mit einen der letzten Versionen bekam das Installationsprogramm eine neue Garderobe verpasst, wobei die eigentlichen Funktionen aber immer noch die gleichen sind. Seit einiger Zeit schleicht sich auch in der Oracle-Produktpalette die typische Look and Feel der unter Windows berhmt gewordenen Assistenten ein und auch das Installationsprogramm liegt bei der 8iVersion im Assistentengewand vor.

26

Oracle erste Schritte

1.2.2

Installation der Version 8

Nach kurzer Ladezeit des Installationsprogramms erhalten Sie eine kleine Dialogbox, mit deren Hilfe Sie fr die Installation das Zielverzeichnis, die gewnschte Sprache und einen symbolischen Namen fr das Installationsziel auswhlen knnen (vgl. Abb. 1.6).

Abbildung 1.6: Auswahl der Sprachoption fr die Oracle-Installation

An dieser Stelle knnen Sie schon den ersten schmerzvollen Fehler machen. Wer wrde an nichts Bses denkend, nicht intuitiv German auswhlen, weil das wenn es schon angeboten wird irgendwie am naheliegendsten ist. Vor ein paar Jahren auf einem Oracle-Seminar war die Aussage des Trainers zu dieser Option ziemlich eindeutig: Sie drfen jede Sprache auswhlen, so lange es Englisch ist. Nach meinem Kenntnisstand gilt dies auch heute noch. Bei der Installation eines Servers sowieso und auch beim Client ist die Sprachoption English meistens die bessere Wahl. Zwar funktioniert der Oracle-Client mit anderen Sprachen einwandfrei, jedoch kann es bei anderen Anwendungen (z.B. PeopleSoft oder ODBC-Datenbankanwendungen) zu seltsamen Anomalien kommen, falls eine andere Sprache gewhlt wurde. Dies uert sich beispielsweise darin, dass Datums- oder Zahlenwerte in der Anwendung nicht korrekt formatiert dargestellt werden. Die hier gewhlte Spracheinstellung fhrt bei Windows-Systemen brigens zum Registrierungseintragung NLS_LANG mit dem Wert AMERICAN_AMERICA. WE8ISO8859P1, den Sie in der Registrierungsdatenbank im Verzeichnis \HKEY_ LOCAL_MACHINE\SOFTWARE\ORACLE finden. Neben der Sprache haben Sie im letzten Dialog das sogenannte Oracle-Homeverzeichnis f (engl. Home-Directory, z.B. E:\ORANT) festgelegt. Die unter diesem Homeverzeichnis liegende Struktur ist nur von der eingesetzten Oracle-Version abhngig, d.h. sie ist ansonsten konstant und allen Systemanwendungen bekannt. Im brigen ist es auch mglich, auf einem Rechner mehrere parallele Installationen zu erstellen. In dem Fall existieren blicherweise auch entsprechend viele Oracle-Homeverzeichnisse. Werden nun auf dem Server irgendwelche Anwendungen gestartet, so holen sich diese zunchst einmal das Homeverzeichnis mit Hilfe einer Umgebungsvariablen oder eines Registrierungseintrags ab, weshalb beispiels-

Installation

27

weise unter Unix in vielen Skripten immer mal wieder die oracle_home-Umgebung exportiert wird. Wenn Sie unter NT mehrere Installationen durchfhren und dabei andere Home-Verzeichnisse whlen, dann mssen Sie darauf achten, dass vor dem Start der Anwendungen das richtige Home-Verzeichnis ausgewhlt ist, und falls nicht, dann mssen Sie es vor dem Programmstart entsprechend einstellen, wofr Sie nach der Installation in der Oracle-Programmgruppe ein kleines Utility finden. Was folgt, ist eine weitere Dialogbox (vgl. Abb. 1.7) mit einem Hinweis, den Sie ebenfalls durchaus ernst nehmen sollten.

Abbildung 1.7: Eintragung des richtigen Suchpfades fr DLLs und Programme

Unter Windows werden Informationen ber Speicherorte (Home- und andere Verzeichnisse) in der Windows-Registrierungsdatenbank gespeichert. Hier kann also jede Anwendung Informationen abrufen, die zur Ausfhrung von bestimmten Programmen oder zum Laden von DLLs gebraucht werden. Allerdings arbeitet nicht (oder noch nicht ?) jedes Programm auf diese Weise. Es gibt noch viele Anwendungen, die zum Laden solcher Bibliotheken Hilfestellung in Form von voreingestellten Suchpfaden bentigen. Wenn Sie den Dialog mit der Yes-Schaltflche verlassen, dann trgt Oracle den richtigen Suchpfad fr Programme und DLLs in die Windows-Systemvariable path ein. Beenden Sie den Dialog mit No sofern Sie sicher sind, dass Sie keinen solchen Pfad-Eintrag brauchen bzw. Sie die notwendige Einstellung spter selbst vornehmen wollen. Kleine Ursache groe Wirkung. Das gilt unter Umstnden auch fr diesen PfadEintrag. Ich habe in meiner Laufbahn schon Trouble-Tickets zu diesem Thema bearbeitet. Die Oracle-Installation war erfolgreich, die Datenbank konnte ohne erkennbare Fehler generiert und geladen werden, der Zugriff auf die Datenbank mit Hilfe von Oracle-Tools (z.B. SQL-Worksheet oder SQL*Plus) funktioniert ebenfalls und auch die Anwendung wurde ohne Fehler installiert. Trotzdem luft sie nicht, d.h. der Zugriff auf die Datenbank klappt nicht. Manchmal war dieser Pfad-Eintrag die Ursache des bels. Denken Sie vor allem auch daran: selbst wenn Sie den Client mit Hilfe des Oracle-Installers installieren und dabei den Pfad setzen lassen - in machen Firmen existieren eigenwillige Login-Scripts, die diese Pfad-Angabe beim Anmelden des Benutzers selbst setzen bzw. berschreiben.

28

Oracle erste Schritte

Zurck zur Installation. Mit Hilfe des nchsten Dialogs mssen Sie die gewnschte Art der Installation auswhlen. In meiner vorliegenden Version habe ich hierbei drei verschiedene Varianten zur Auswahl (vgl. Abb. 1.8).

Abbildung 1.8: Was soll installiert werden?

Die voreingestellte Option Oracle8 installiert vorgegebene Komponenten des Servers und des Clients. Die nchste Option Oracle8 Client wird bentigt, wenn beispielsweise der Oracle-Client auf weiteren Arbeitsstationen installiert werden soll und die letzte Option ermglicht Ihnen die manuelle Auswahl aller gewnschten Komponenten. Da spter jederzeit beliebige Komponenten nachinstalliert werden knnen, ist gegen eine Standardinstallation eigentlich nichts einzuwenden. Also klicke ich auf OK und setze den Installationsvorgang damit fort. Fr alle mglichen Installationsvarianten gilt im brigen, dass bestimmte ausgewhlte Komponenten whrend des Installationsvorgangs zu spezifischen kleinen Dialogen fhren knnen, in denen dann irgendwelche Einstellungen vorgenommen werden knnen. Welche Optionen in an dieser Stelle genau angeboten werden, hngt natrlich vom Inhalt der eingelegten CD ab. So existieren beispielsweise auch CDs, auf denen nur der Oracle Client verfgbar ist. In meinem Beispiel, also der Installation des Oracle-Servers auf einem NT-Laptop, werden sowohl die Programme des Servers also auch des Clients in das gemeinsame Oracle-Home-Verzeichnis (z.B. E:\ORANT) installiert. Das wre bei einem NT-Server im brigen zunchst einmal nicht anders, denn auch auf einem Server kann sich ein Anwender theoretisch anmelden und anschlieend gewhnliche Anwendungsprogramme starten. Starterdatenbank generieren Aufgrund der gewhlten Installationsmethode erscheint als Nchstes ein Dialog (Abbildung 1.9), der es mir ermglicht zusammen mit der Installation auch gleich eine Datenbank anzulegen. Es gibt viele Wege nach Rom dies ist sicherlich der einfachste, eine Oracle-Datenbank zu erhalten. Im Kapitel Erstellen einer Datenbank werden Sie einen anderen, weitestgehend manuellen, Weg zur Erstellung einer Datenbank kennen lernen.

Installation

29

Abbildung 1.9: Starterdatenbank installieren

Die Option Typical fhrt zur Installation einer Datenbank mit dem Namen ORACLE und der Instanzbezeichnung ORCL (=SID). Diese Datenbank ist von ihrem Aufbau bzw. Konfiguration zum Spielen und Ausprobieren (z.B. fr die bungen in diesem Buch) gar nicht so schlecht geeignet und im brigen kann man ja im Nachhinein auch alle fehlenden Parameter ergnzen oder vorhanden Einstellungen nach Belieben ndern. Mit der Option None wird nur das Oracle-Softwarepaket installiert. Die mittlere Option ruft nach der Installation der Software den Oracle-Datenbank Assistenten auf. Mit Hilfe dieses Assistenten knnen Sie die bentigte Datenbank direkt erstellen oder Sie lassen sich die zur spteren Erstellung bentigten Skripte generieren. Im Kapitel Erstellen einer Datenbank werden Sie mehr ber dieses Werkzeug erfahren. Auch nach diesem Dialog ist die Installationsfragestunde noch nicht beendet. Der nchste Dialog klrt die Frage, ob die Oracle-Dokumentation auf die Festplatte kopiert oder von der CD aus gestartet werden soll. Eine Kopie beansprucht zur Zeit zwar immerhin ca. 70MB, aber die lohnen sich allemal. Beenden Sie nun auch diesen letzten Dialog, wodurch der Oracle-Installer mit der eigentlichen Installationsarbeit beginnt. In unserem Fall werden hierbei nicht nur die bentigten Programme und Dateien in das vorgegebene Verzeichnis kopiert, sondern whrend der Installation wird auch unsere erste Datenbank angelegt (Mehr Informationen zum Aufbau der Starterdatenbank finden sie brigens im Kapitel 3 Starter Database Contents im Buch Oracle8 Getting Started for Windows NT). Nach ein paar Minuten das hngt natrlich vom Rechner ab erscheint dann (hoffentlich) die folgende Meldung (vgl. Abb. 1.10), die uns die erfolgreich abgeschlossene Installation quittiert.

Abbildung 1.10: Das wars, die Installation wurde erfolgreich beendet

30

Oracle erste Schritte

Sollten Sie brigens bei einer Erst- bzw. Vollinstallation Probleme haben, dann ist neben zu wenig Plattenplatz auch immer ein vorhergehender misslungener Installationsversuch bzw. eine nicht vollstndige Deinstallation ein mglicher Grund dafr. Etwas weiter unten im Kapitel Installation entfernen finden Sie ein paar Hinweise, was Sie alles kontrollieren sollten, um dies als Grund auszuschlieen. Die Installation begutachten Wenn man Oracle zum ersten Mal installiert, dann lohnt es sich schon ein wenig genauer hinzuschauen, was alles Neues im System und auf der Festplatte verteilt wurde. Mit Hilfe der Abbildung 1.11 erhalten Sie einen berblick, was whrend der Installation alles auf Ihrem Rechner erstellt wurde.

Abbildung 1.11: Optischer berblick des Installationsergebnisses

Zunchst einmal liefert die Standardinstallation zwei neue Programmgruppen. Beide enthalten eine Flle von Werkzeugen, die Sie zum Teil im weiteren Verlauf dieses Buches noch kennen lernen werden. Wie Sie in dem Ausschnitt rechts oben der Abbildung sehen, entsteht in dem vorgegebenen Oracle-Zielverzeichnis eine ziemlich komplexe Verzeichnisstruktur. Ebenfalls umfangreich sind die in der Windows-Registrierung erstellten Eintrge. Interessant ist auch der Ausschnitt im mittleren Teil der Abbildung. Dort sehen Sie, dass auch verschiedene neue Dienste erstellt wurden. Besonders wichtig hierbei sind vor allem diejenigen, die zum Betrieb unserer Starterdatenbank bentigt werden (OracleServiceORCL, OracleStartORCL und OracleTNSListener80).

Installation

31

Nachinstallieren Ein weiteren guten berblick ber soeben installierte Komponenten erhalten Sie auch, wenn Sie jetzt einfach mal den ebenfalls installierten Oracle-Installer, den Sie in der Programmgruppe Oracle for Windows NT finden, aufrufen (Abbildung 1.12).

Abbildung 1.12: Hauptfenster des Oracle-Installers

Im Prinzip besteht das Hauptfenster des Installationsprogramms aus zwei Listen. In der rechten Liste finden Sie eine Aufstellung der bereits installierten Komponenten und in der linken haben Sie eine Auswahl der installierbaren Komponenten. Der Rest drfte eigentlich intuitiv klar sein. Markieren Sie beliebige Eintrge in der rechten Liste, um sie anschlieend durch Drcken der Schaltflche Remove zu entfernen. Oder Sie whlen die bentigten Eintrge in der linken Liste aus, um sie mit Hilfe der Install-Schaltflche zu installieren. Alle verfgbaren Komponenten sind in Oracle zu Paketen zusammengefasst, die technisch durch sogenannte Product Files (*.PRD) reprsentiert werden. Mit Hilfe der From-Schaltflche haben Sie die Mglichkeit diese Produktpakete auszuwhlen bzw. zu ffnen.

32

Oracle erste Schritte

Installation entfernen Wie einzelne Komponenten installiert oder entfernt werden knnen, haben Sie im vorhergehenden Kapitel gesehen. Eigentlich nicht erwhnenswert ist, dass Sie mit Hilfe des Oracle-Installers die ganze Installation lschen knnen, indem Sie alle in der rechten Liste angezeigten Komponenten markieren und danach die Schaltflche Remove bettigen. Allerdings klappt dieser Vorgang nicht immer so reibungslos, wie die vorhergehende Installation. Manchmal ist ein manueller Clean-Up notwendig; eine Kontrolle ist in jedem Falle empfehlenswert. Im Folgenden finden Sie einen mglichen Putzplan, um Ihre Oracle-Installation wieder zu entfernen:

: : : : : : :

Beenden und Deaktivieren Sie mit Hilfe der Systemsteuerung alle eventuell noch vorhandenen Oraclexxxx-Dienste. Lschen Sie alle installierten Komponenten mit Hilfe des Oracle-Installers. Lschen Sie, sofern noch vorhanden, das Oracle-Verzeichnis (z.B. C:\ORANT). Lschen Sie ggf. die noch vorhandenen Programmgruppen. Kontrollieren Sie die Regestrierungsdatenbank. Lschen Sie ggf. den Eintrag ORACLE im Verzeichnis HKEY_LOCAL_MACHINE\SOFTWARE. Lschen Sie diesen Eintrag ebenfalls im Verzeichnis HKEY_CURRENT_USER\SOFTWARE. Auch die Eintrge der Dienste mssen aus der Windows-Registrierung verschwunden sein oder ansonsten manuell von Ihnen gelscht werden. Sie finden diese Eintrge im Verzeichnis HKEY_LOCAL_MACHINE\SYSTEM\Services. Lschen Sie hier alle Eintrge, die mit Oracle beginnen. Starten Sie Ihren Rechner neu.

Bei Klementine war es nicht nur sauber, sondern immer rein. Bei der Registrierungsdatenbank von Windows schafft auch Ariel das nicht immer, aber sofern Sie die eben genannten Schritte ausfhren, dann ist Ihr System so aufgerumt, dass eine erneute Installation problemlos mglich sein sollte.

1.2.3

Installation von 8i

Die Installation eines 8i-Servers ist zwar nicht grundstzlich anders, sieht aber zumindest vllig anders aus. Das gilt allerdings nicht nur fr die Installation, denn mit dieser Version haben nahezu alle Tools und Werkzeuge neue Beinkleider bekommen. Schon mit dem ersten Bild des Installationsprogramms werden Ihnen verschiedene Mglichkeiten angeboten. Beispielsweise knnen Sie von hier aus die bereits installierten Produkte betrachten oder eine Deinstallation vorhandener Softwarekomponenten einleiten. Uns interessiert im Augenblick natrlich der Installationsvorgang, weshalb wir mit Hilfe der Weiter-Schaltflche den nchsten Installationsschritt einleiten. Der zweite Arbeitsschritt des Installationsvorgangs entspricht im Prinzip der Abbildung 1.6 und dient im Wesentlichen wieder zur Festlegung des Installationsziels und zur Vorgabe des Standardverzeichnisses, das wieder mit der Umgebungsvariable oracle_home verknpft ist. Legen Sie also hier das gewnschte Installationsziel

Installation

33

fest und wechseln Sie wieder mit Hilfe der Weiter-Schaltflche zum nchsten Arbeitsschritt. Dieser entspricht im Vergleich mit der klassischen Variante der Abbildung 1.8, d.h. Sie haben hier die Wahl, verschiedene Produktkategorien auszuwhlen.

Abbildung 1.13: Auswhlen der Produktkategorie bei der 8i-Installation

Ich whle hier die erste Kategorie Oracle8i Enterprise Edition, um einen Datenbankserver mit allen bentigten Komponenten zu installieren. Danach geht es mit der Weiter-Schaltflche zum nchsten Schritt, in dem die Installationsmethode ausgewhlt werden muss. Dabei haben Sie wieder die Auswahl zwischen einer Standardmethode, einem etwas kleiner geschnrten Paketes und der individuellen Auswahl der zu installierenden Komponenten. Ich habe diesmal die individuelle Variante gewhlt (vgl. Abb. 1.14) und mit Hilfe der dargestellten hierarchischen Liste alle Komponenten ausgewhlt, die in etwa einer klassischen 8er-Installation entsprechen. Natrlich knnen Sie fehlende Komponenten wieder jederzeit nachinstallieren. Falls Sie sich berhaupt nicht sicher sind oder Ihre erste Installation ausfhren und gengend Plattenplatz zur Verfgung haben, dann spricht auch nichts dagegen, die Standardinstallationsmethode zu verwenden, so dass auch automatisch wieder eine Starterdatenbank angelegt wird. Bei der manuellen Installationsvariante erhalten Sie im nchsten Arbeitsschritt einen Dialog, in dem abgefragt wird, ob Sie zusammen mit der Installation eine Starterdatenbank generieren mchten. Ich lehne diesmal dankend ab und wechsele zum nchsten und letzten Dialog des Installationsassistenten, in dem Ihnen noch einmal das geplante Installationsszenario (vgl. Abb. 1.15) gezeigt wird.

34

Oracle erste Schritte

Abbildung 1.14: Manuelle Auswahl der installierbaren Komponenten

Abbildung 1.15: Anzeige der geplanten 8i-Installation

Dienste unter Windows-NT

35

Nach Auswahl der Schaltflche Installieren beginnt das Programm damit, die bentigten Dateien von der CD zu kopieren. Dabei muss man eindeutig feststellen, dass die Angelegenheit im Vergleich zu frher eindeutig lnger dauert. Auerdem muss ich hier noch einmal meinen Schrecken ber den bentigten Platzbedarf kundtun, von dem ich mich bis heute noch nicht ganz erholt habe, denn trotz meiner zurckhaltenden Auswahl hat die Installation ca. 700 MB auf meiner Festplatte gefressen. Das wre Stoff fr folgende Schlagzeile der sich vom ersten Schock leicht erholte Patient verstarb vollends, nachdem er feststellte, dass in dieser Menge noch keine Datenbank und keine Dokumentation enthalten war.

1.3 Dienste unter Windows-NT : Mit Hilfe des eben beschriebenen Installationsprogramms haben Sie nun Oracle

oder Oracle 8i auf Ihrem Rechner installiert und eventuell auch Ihre erste Oracle-Instanz (SID=orcl) mitsamt zugehriger Datenbank generiert. Durch die standardmige Installation und die Generierung der Starterdatenbank wurden in Ihrem Windows-Betriebssystem eine Reihe von Diensten eingetragen, die den Betrieb der Datenbankinstanz vereinfachen (vgl. Abb. 1.16).

Abbildung 1.16: Wichtige Dienste zum Betrieb der Oracle-Instanz

: :

Von den insgesamt installierten Diensten sind fr den Betrieb der Starterdatenbank aber nur folgende drei notwendig, wobei die vom System konkret vergebenen Dienstnamen zum einen von der installierten Oracle-Version und zum anderen von dem von Ihnen vorgegebenen Namen fr das Homeverzeichnis abhngt: OracleServiceORCL Dieser Dienst startet die fr die Datenbank bentigten Instanz. Entsprechend den letzten Buchstaben der Dienstbezeichnung wird hierbei die Instanz ORCL (=SID) gestartet. OracleStartORCL Dieser Dienst veranlasst die Instanz zum ffnen der zugehrigen Datenbank. Einmal gestartet, verrichtet dieser Dienst die beschriebene Aufgabe und frisst anschlieend kein Brot mehr. Sie knnen ihn also laufen lassen; Sie knnten

36

Oracle erste Schritte

ihn auch beenden, fr die Betriebsbereitschaft der Oracle-Datenbank spielt das keine Rolle. OracleTNSListener80 Wenn Sie das Grundlagen-Kapitel vollstndig gelesen haben, dann erinnern Sie sich vielleicht an den schematischen Aufbau eines Client/Server-Systems (Abbildung 1.2). Dieser Dienst reprsentiert genau den auf dem Server beschriebenen Nachrichtendienst. Er muss also laufen, damit eine Kontaktaufnahme mit der Datenbank mglich ist.

Wenn Sie eine Installation auf einem NT-Server durchfhren, dann ist es sicherlich sinnvoll alle diese Dienste mit dem Start von NT auch automatisch zu starten, d.h. als Startart fr diese drei Dienste wre Automatisch so wie in der Abbildung 1.12 - die richtige Einstellung. Auf meinem Notebook habe ich aber keine Lust, dass mir im Hintergrund permanent Ressourcen geklaut werden, obwohl ich gerade gar keine Datenbank brauche, weil ich vielleicht nur einen Brief schreibe. Oder von allen installierten Datenbanken braucht man je nach Aufgabenstellung gerade nur eine spezielle Auswahl. In all diesen Fllen knnen Sie die nicht bentigten Datenbankinstanzen beenden, indem Sie die zugehrigen Dienste mit Hilfe der Systemsteuerung beenden. Die Reihenfolge, in der Sie die einzelnen Dienste beenden ist dabei gleichgltig. Beachten Sie allerdings, dass der Dienst OracleTNSListener80 laufen muss, wenn Sie mit wenigstens einer Datenbankinstanz arbeiten wollen. Wenn die Nichtbenutzung der Datenbankdienste eher die Regel als die Ausnahme ist, dann sollten Sie die Startart dieser Dienste auf Manuell abndern, damit mit dem Starten Ihres Rechners keine Oracle-Instanzen hochgefahren werden. Bei Bedarf knnen Sie die bentigten Datenbankdienste jederzeit mit Hilfe der Windows-Systemsteuerung aktivieren; die Reihenfolge in der Sie die einzelnen Dienste aktivieren ist dabei gleichgltig. Wenn Sie beispielsweise zuerst den Dienst OracleStartORCL starten, dann werden Sie feststellen, dass diese Aktion im Hintergrund auch den Start des Dienstes OracleServiceORCL und damit das Hochfahren der zugehrigen Datenbankinstanz bewirkt. Bei so viel Arbeit macht es vielleicht Sinn, sich fr dieses Hoch- und Runterfahren einen Liftboy anzuschaffen, der einem die Arbeit abnimmt und nur noch auf die Kommandos hoch bzw. runter bitte hrt. Windows-NT bietet Ihnen standardmig die Mglichkeit, sich einen solchen Diener zu basteln. Mit Hilfe des NETKommandos knnen Sie jeglichen installierten Dienst hoch- oder runterfahren. Konkret werden die hier bentigten NET-Befehle in einer Stapelverarbeitungsdatei (ich finde BATCH klingt besser) zusammengefasst und fr diese BATCH-Datei erstellen Sie einfach eine Verknpfung in einer Programmgruppe oder sogar direkt auf Ihrem Desktop. Die Batchdatei zum Starten der Dienst (CD: \SCRIPT\START_ORCL.BAT) knnte etwa folgendermaen aussehen:

Verbindung zur Datenbank herstellen

37

rem rem net net net

Starten des Listeners, Starten der Oracle-Instanz ORCLffnen der Datenbank start OracleTNSListener80 start OracleStartORCL stop OracleStartORCL

Listing 1.1: Starten der Datenbank mit Hilfe von Net-Kommandos

Ganz hnlich sieht das bentigte Skript zum Beenden der ORCL-Datenbankinstanz (CD: \SCRIPT\STOP_ORCL.BAT) aus:
rem net net net Stoppen des Listeners, Stoppen der Datenbank ORCL stop OracleTNSListener80 stop OracleStartORcL stop OracleServiceORCL

Listing 1.2: Stoppen einer Datenbank mit Hilfe von Net-Kommandos

Auf hnliche Weise knnen Sie sich fr jede denkbare Kombination von Datenbankdiensten entsprechende Skripte erstellen. Wenn Sie bei deren Ausfhrung versuchen einen schon laufenden Dienst (z.B. OracleTNSListener80) noch einmal zu starten, dann ist das nicht weiter schlimm; Sie erhalten in dem Fall lediglich eine entsprechende Warnmeldung.

1.4

Verbindung zur Datenbank herstellen

Die Installation einer Oracle-Datenbank luft dank der mitgelieferten Installationsprogramme zwischenzeitlich unproblematisch und zeitgem. Dennoch gibt es im Rahmen der ersten Experimente und Gehversuche in der Regel zwei zunchst unsichtbare Hrden mit erheblichem Frustpotential, die es zu berwinden gilt. Zum einen haben Sie im Rahmen der Installation jetzt eine Datenbank - nebst einer Menge Werkzeuge zur Bearbeitung derselben - auf Ihrem Rechner laufen, jedoch ist die Verfahrensweise zur Kontaktaufnahme noch vllig ungeklrt und ohne weitere Eingriffe auch nicht mglich. Zum anderen hegen Sie in Ihrem inneren vielleicht den Wunsch, selbstndig eine eigene Datenbank zu erstellen. Aufgrund der Architektur von Oracle (z.B. eine Instanz pro Datenbank) ist das nicht ganz so einfach wie in manch anderem DBMS-Systemen. Ein Befehl der Form create database reicht hier alleine jedenfalls nicht aus. Falls Sie an einem dieser beiden Probleme schon einmal verzweifelt sind, so kann ich Sie trsten: Willkommen im Club, Sie sind nicht der erste, einzigste und sicherlich auch nicht der letzte, der sich bei diesen Aufgaben irgendwann einmal mit scheinbar unberwindbaren Problemen konfrontiert sah. Doof ist eigentlich nur, dass das Ganze eigentlich ganz einfach ist, aber im Nachhinein ist man ja immer schlauer. In diesem Kapitel will ich Ihnen im Folgenden die Kontaktaufnahme mit Ihrer Datenbank etwas nher bringen und im nchsten Kapitel beschftigen wir uns dann mit dem Erstellen eigener Datenbanken. Allerdings werde ich Ihnen hierbei nur soviel technische und theoretische Hintergrundinformationen liefern wie unbedingt

38

Oracle erste Schritte

notwendig ist, damit Sie zum einen wissen worum es berhaupt geht und zum anderen in der Lage sind, Ihre eigene Installation oder die Installation in einem kleinen Netzwerk erfolgreich durchfhren zu knnen. Zum Thema Oracle Networking knnte man mittlerweile ein eigenes umfangreiches Buch erstellen. Ich will daher gar nicht erst den Versuch unternehmen, dieses komplexe Thema im Rahmen des Workshops irgendwie umfassend oder zusammenhngend abzuhandeln.

1.4.1

Einfhrung in SQL*Net bzw. Net8

Das Zauberwort fr die Verbindungsherstellung zu einer Oracle-Datenbank heit SQL*Net., wobei man entsprechend der aktuellen Version mittlerweile auch nur noch von Net8 spricht. Dieser Begriff hat aber berhaupt nichts mit SQL zu tun und die Entscheidung, ob das Ganze nett ist, berlasse ich getrost Ihnen. Vielmehr handelt es sich hierbei um eine Art berprotokoll, das zwischen der Anwendung und dem eigentlichen Netzwerk gelagert ist (vgl. Abb. 1.17).

Client Anwendung Net8 Oracle Protokoll-Adapter Netzwerkprotokoll

Server Oracle-DBMS Net8 Oracle Protokoll-Adapter Netzwerkprotokoll

Physisches Netzwerk
Abbildung 1.17: Schema der Net8-Kommunikation

Will eine Anwendung Verbindung mit einer Datenbank aufnehmen, dann fordert sie diese quasi ganz abstrakt, d.h. ohne Bercksichtigung irgendwelcher physischen Gegebenheiten, ber Net8 an. Das Gleiche gilt auch, wenn das Anwendungsprogramm Daten versenden will oder auf den Empfang von Daten vom Server wartet. Das Anwendungsprogramm muss sich in keinem Fall selbst um die durch das Netzwerkprotokoll vorgegebenen Regeln bei der Kommunikation kmmern. Diese Art der Kommunikation bezeichnet Oracle brigens mit dem Begriff Transparent Network Substrate, was an vielen Stellen einfach mit TNS abgekrzt wird. Die von der Anwendung gestellten Verbindungsanforderungen werden von Net8 mit Hilfe des installierten Oracle-Protokoll-Adapters fr das konkret vorhandene Netzwerk bersetzt bzw. an dieses bergeben. Das Verfahren wird sowohl auf dem Client als auf dem Server angewendet und funktioniert in beide Richtungen.

Verbindung zur Datenbank herstellen

39

Fr uns Nichtnetzwerker hat Net8 den Nachteil, dass wir selbst bei der Installation einer kleinen Spiel- oder bungsdatenbank bestimmte Konfigurationseinstellungen durchfhren mssen, damit das in Abbildung 1.17 dargestellte Sandwich entsprechend durchlssig ist. Aber hren wir auf zu jammern, die Vorteile dieser Architektur berwiegen mehr als eindeutig:

Stellen Sie sich einmal vor, jemand erfindet ein neues Netzwerkprotokoll. In dem Fall mssen Sie nur auf die Verfgbarkeit des passenden Oracle-ProtokollAdapters warten. Weder Ihre Anwendung noch der Oracle-Server selbst mssen in irgendeiner Form angepasst werden. Was bei einfachen Strukturen vielleicht ein wenig kopflastig erscheint, zeigt seine wahren Strken erst bei komplexeren Netzwerken. Stellen wir uns hierzu zwei Datenbanken, eine auf einem NT- und die andere auf einem NOVELL-Server vor. Jetzt haben wir es blicherweise mit zwei Netzwerkprotokollen (TCP/IP und SPX), d.h. wir installieren einfach diese beiden Oracle-Protokoll-Adapter. Grundstzlich wird durch Net8 die Verwendung verschiedener Netzwerkprotokolle oder einer Server/Server-Verbindung wesentlich vereinfacht. Die genaue Arbeitsweise der Verbindungsschicht zwischen Anwendung und DBMS wird mit Hilfe von Konfigurationsdateien gesteuert. Bei einem Versionswechsel mssen Sie in der Regel daher lediglich die entsprechenden Programme und Bibliotheken austauschen. Die alten Konfigurationsdateien bilden anschlieend zusammen mit der neuen SQL*Net-Version wieder genau das gleiche logische Oracle-Netzwerk wie vorher ab. Dieser Vorteil gilt im brigen auch, wenn Sie mit verschiedenen SQL*Net bzw. Net8-Versionen parallel arbeiten mssen. Immerhin gibt es noch reichlich klassische (16-Bit) Windows-Anwendungen und diese bentigen fr Ihren Betrieb die Installation des Oracle-Clients fr Windows. Gerade der 16-Bit-Client fr Windows und der NT-Client laufen auf einem Rechner problemlos nebeneinander, wobei Sie die Net-Konfigurationsdateien fr beide Installationen verwenden knnen. Die Net8-Architektur vereinfacht die Bereitstellung zentraler Hilfsmittel, beispielsweise zur Fehleranalyse oder zur Verschlsselung der bermittelten Daten. Ein entsprechend bentigter Service wird einfach in der zughrigen Konfigurationsdatei ein- bzw. ausgeschaltet. Bleiben wir mal bei der Verschlsselung der bermittelten Daten: Wird eine solche Option gewhlt, dann gilt sie automatisch fr alle eingesetzten Anwendungsprogramme, ohne das in diesen irgendetwas gendert oder angepasst werden muss.

Bei der Verbindungsanforderung von einem Anwendungsprogramm zum OracleDBMS spielt allerdings noch eine weitere Komponente eine Rolle, die Sie bisher zwar schon gesehen haben, deren genaue Funktion bis jetzt aber noch nicht besprochen wurde. Es handelt sich hierbei um den auf dem Server laufenden Listener-Prozess, den Sie bei einer standardmigen NT-Installation als Dienst OracleTNSListener80 kennen gelernt haben. Dieser Dienst hrt permanent das Netzwerk ab und dient quasi als zentrale Empfangsstation aller eingehenden Verbindungsanfragen.

40

Oracle erste Schritte

Wie schon gesagt, kann der genaue Name dieses Dienstes variieren, d.h. der standardmig vergebene Name hngt von der verwendeten Version und Ihren Installationsvorgaben ab. Die Wrtchen TNS und Listener tauchen aber im Regelfall immer auf, so dass der von mir gemeinte Dienst eigentlich immer zu identifizieren ist. Dadurch wird das eigentliche DBMS von dieser Horchaufgabe entlastet. Stellen Sie sich mal einen Busfahrer (DBMS) vor, der neben seiner Fahrttigkeit auch noch permanent auf alle Fahrgste achten muss, ob an der nchsten Haltestelle jemand aussteigen will. Whrend der Fahrt reden sowieso alle Gste (Clients) durcheinander und trotzdem msste der Fahrer permanent auf signifikante Begriffe (z.B. Stop) achten. Da ist es doch einfacher, man installiert einen Listener in Form eines roten Stopknpfchens und wenn ein Client (Fahrgast) diesen drckt, dann erhlt der Fahrer (DBMS) diese Aufforderung ganz automatisch (weil es bei ihm vorne klingelt) ohne sich um den Erhalt der Information kmmern zu mssen. Solche Listener knnen das Netzwerk fr mehr als ein DBMS abhren. Fr welche sie es konkret tun, das muss ebenfalls im Rahmen der Net8-Konfiguration festgelegt werden. Fr mich sind im Rahmen meiner Beraterttigkeit solche Dinge, genau wie Netzwerke, Rechnerarchitekturen u.., immer Mittel zum Zweck. In der Regel sie genau wie eine Net8-Installation beim Kunden sowieso von entsprechenden Spezialisten geplant und konfiguriert. Trotzdem ist es natrlich interessant zu wissen, worum es eigentlich geht; schlielich will man ja mitreden knnen und hierzu haben Sie, so denke ich, jetzt genug Informationen bekommen. Das ganze Spektrum der Net8Konfiguration und Mglichkeiten finden Sie natrlich wieder in der Oracle-Dokumentation, und zwar im Buch Oracle8 Networking bzw. Oracle8i Server Networking.

1.4.2

Verbindung zur Starterdatenbank herstellen

Nun geht es endlich los, wir kmmern uns um die Verbindung zu unserer Starterdatenbank. Standardmig befinden sich die Net8-Konfigurationsdateien im \NET80\ADMIN-Verzeichnis bzw. bei der 8i-Version im \NETWORK\ADMIN, dass selbst wiederum unterhalb des Oracle-Homveverzeichnisses (z.B. E:\ORANT) angelegt ist. Beim alten 16-Bit-Client heit der zugehrige Pfad brigens auch \NETWORK\ADMIN (also Back to the Roots) und befindet sich im entsprechenden Home-Verzeichnis der 16-Bit-Installation (z.B. C:\ORAWIN). Keine Regel ohne Ausnahmen, das gilt natrlich auch hier. Gerade in greren Unternehmen werden Sie in der Windows-Registrierung fters den Schlssel TNS_ADMIN im Verzeichnis \HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE finden. Mit Hilfe dieses Eintrags knnen Sie den Ort fr die Konfigurationsdateien des Net8-Zugriffs festlegen, beispielsweise um die entsprechenden Dateien zentral bereitzustellen. Bedenken Sie: Je nach Softwarearchitektur wird der Oracle-Client ggf. auf jeden Arbeitsplatzrechner installiert. Da sich der Client nicht tglich ndert und wegen den heutzutage mglichen Verfahrensweisen der automatischen Softwareverteilung ist das eigentlich auch nicht weiter dramatisch. Aber schnell

Verbindung zur Datenbank herstellen

41

reagieren kann man auf diese Weise sicherlich nicht. Bei einer solchen Installation mssten aber auch alle Konfigurationsdateien auf die lokalen Arbeitsplatzrechner kopiert werden und wie Sie gleich sehen werden, ndern sich diese, wenn beispielsweise eine neue Datenbank angelegt wird oder sich irgendwelche Servernamen oder Adressen ndern. Die neue Net8-Konfiguration msste jetzt ebenfalls auf alle Rechner bertragen werden. Da ist es schon sinnvoll, die Steuerungsdateien des Net8-Netzwerks auf einem zentralen Dateiserver bereitzustellen; mit Hilfe von TNS_ADMIN ist das kein Problem. Den Listener konfigurieren Beginnen mchte ich mit der Konfiguration des Listeners. Hierzu finden Sie auf dem Server, ebenfalls im \NET80\ADMIN- bzw. \NETWORK\ADMIN Verzeichnis die Datei LISTENER.ORA. Der Aufbau der Datei ist meisten relativ einfach bzw. sie enthlt nur wenige Parameter, weshalb eine Anpassung auch per Hand mglich ist. Im Rahmen der Installation wird brigens meistens schon eine Beispieldatei mit verschiedenen Eintrgen erstellt und in jedem Fall finden Sie auf der Begleit-CD ein Muster unter dem Namen \NET80\LISTENER.ORA. hnlich wie eine Windows-Konfigurationsdatei enthlt auch die Datei LISTENER.ORA neben Kommentaren verschiedene Einstellungen, die mit Hilfe spezieller Schlsselwrter in der Form Schlssel = Wert festgelegt werden.
# Ich bin ein Kommentar STARTUP_WAIT_TIME_LISTENER = 0

Die vom Listener abzuhrenden Protokolle und Adressen werden mit Hilfe des Schlsselwortes LISTENER in Form einer Adress-Parameter-Liste angegeben. Das nachfolgende Beispiel zeigt die Konfiguration fr einen Listener, der ebenfalls den Namen LISTENER erhlt und auf dem Rechner ray_dell (hier knnte auch eine IPAdresse stehen) die Ports 1521 und 1526 berwacht:
LISTENER = (ADDRESS_LIST = (ADDRESS= (PROTOCOL= TCP) (Host= ray_dell) (Port= 1521) ) (ADDRESS= (PROTOCOL= TCP) (Host= ray_dell) (Port= 1526) ) )
Listing 1.3: Konfiguration der Ports fr den Listener-Prozess

In unserem Beispiel mssen Sie den Rechnernahmen natrlich gegen den Namen bzw. die Adresse Ihres Datenbankservers austauschen. Wie schon erwhnt, kann so ein Listener fr mehrere Datenbanksysteme zustndig sein. Luft auf dem Rechner mehr als eine Datenbankinstanz, so mssen Sie die zum Listener gehhrenden Instanzen mit Hilfe des Parameters SID_LIST_LISTENER festlegen. Dabei schadet es natrlich nicht, wenn Sie den Parameter auch bei nur einer Datenbankinstanz eintragen:

42

Oracle erste Schritte

SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (GLOBAL_DBNAME = oracle) (SID_NAME = ORCL) ) (SID_DESC = (GLOBAL_DBNAME = datab01) (SID_NAME = db01) ) )
Listing 1.4: Festlegen der Horchliste fr den Listener

Wie Sie an dem Beispiel erkennen knnen, besteht die eben beschriebene Instanzenaufzhlung im Wesentlichen aus der Benennung des Datenbanknamens nebst zugehriger Instanzbezeichnung (SID). Fr die Starterdatenbank war der Datenbankname oracle und die Instanz wurde mit orcl bezeichnet. Spter im Kapitel 1.5 werden Sie erfahren, wie diese Begriffe zustande kommen. Auerdem habe ich dem Listener schon einmal angewiesen, den Abhrdienst auf fr die noch zu erstellende Datenbank (datab01, SID=db01) aufzunehmen. Wenn Sie nderungen in der Konfigurationsdatei vornehmen, dann werden die erst wirksam, wenn Sie den Listener runter und anschlieend wieder hochfahren. Auerdem knnen Sie mit Hilfe verschiedener Parameter (vgl. nachfolgenden Verweis auf die Dokumentation) die Protokollfunktion des Listeners ein- bzw. ausschalten oder den Namen bzw. den Ort des Protokolls festlegen. Standardmig ist die Protokollfunktion eingeschaltet und Sie finden die Ausgabe LISTENER.LOG in dem \NET80\LOG- bzw. \NETWORK\LOG-Verzeichnis. Weitere Informationen ber die Parametrierung des Listeners bzw. zu den Einstellungen in der Datei LISTENER.ORA finden Sie wie immer in der Oracle-Dokumentation, vor allem in den Kapiteln des Buches Net8 Administrators Guide. Eine vollstndige bersicht aller vorhandenen Parameter finden Sie bei der Version 8 dort im Anhang B Configuration Parameters, d.h. genauer im dortigen Kapitel B.4 Listener Parameters (LISTENER.ORA). Bei der 8i-Version ist aus diesem B ein C geworden, der eigentlich Titel des Anhangs ist aber gleich geblieben. Listener-Verwaltung Wie schon gesagt, handelt es sich bei dem Listener um einen Hintergrundprozess, der unter Windows-NT mit Hilfe eines entsprechenden Dienstes verwaltet wird. Damit stellt sich die Frage, wie dieser Dienst berhaupt zustande kam, was prinzipiell zu tun ist, wenn Sie einen weiteren Listenerprozess installieren mchten oder wenn aus irgendwelchen Grnden whrend der Installation kein passender Windows-Dienst generiert wurde. Zu diesem Zwecke existiert ein Programm, das auf den Namen LSNRCTL80.EXE bzw. LSNRCTL.EXE bei 8i hrt und eine Art Listener-Konsole reprsentiert. Das Programm knnen Sie in einem MS-DOS-Fenster starten, wobei sich nach dem Start (vgl. Abb. 1.18) zunchst einmal nur der angezeigte Eingabeprompt ndert.

Verbindung zur Datenbank herstellen

43

Abbildung 1.18: Starten der Listener-Konsole bei einer 8i-Installation

Das Programm bietet Ihnen eine ganze Reihe von Mglichkeiten, wobei Sie vorhandene Kommandos angezeigt bekommen, wenn Sie am Prompt den Befehl help eingeben. Die Bedeutung weiterer wichtiger Kommandos knnen Sie der Tabelle 1.2 entnehmen.
Kommando start <listener> Beschreibung startet den spezifizierten Listener. Da die Konfigurationsdatei fr den Listener heit LISTENER.ORA, und dort wurde durch Eintrag LISTENER= der Name des Listeners festgelegt. Bei mehreren Listener existieren in dieser Datei auch entsprechend viele Eintrge (z.B. LISTENER01= usw.). Durch die Eingabe des Befehls start listener knnen Sie also den in der Datei definierten Listener starten. Hierdurch erhalten Sie beispielsweise auch einen verlorengegangenen Windows-Dienst zurck. stoppt den angegebenen Listener-Prozess. zeigt den aktuellen Status des vorgegebenen Listeners am Bildschirm an. aktiviert eine genderte Listenerkonfiguration. beendet das Programm.

stop <listener> status <listener> reload <listener> exit

Tabelle 1.2: Wichtige Kommandos der Listener-Konsole

Den Client konfigurieren Der Net8-Client wird im Minimum mit Hilfe der Dateien SQLNET.ORA und TNSNAMES.ORA konfiguriert. Im Unterschied zur Datei LISTENER.ORA befinden sich diese Dateien meistens nicht nur auf jedem Client, sondern ebenfalls auch auf dem Server, und zwar in beiden Fllen wieder im \NET80\ADMIN- bzw. \NETWORK\ADMIN-Unterverzeichnis des Oracle-Homeverzeichnisses. Sofern ein TNS_ADMIN-Eintrag in der Windows-Registrierung vorliegt befinden sich die Dateien natrlich an dem dort spezifizierten Ort. hnliches gilt auch, wenn wei-

44

Oracle erste Schritte

tere Net8-Clients (z.B. 16-Bit Windows) installiert wurden, d.h. in den Fllen mssen die Konfigurationsdateien zustzlich in alle \NET80\ADMIN- bzw. \NETWORK\ADMIN-Unterverzeichnisse kopiert werden. Wenn Sie sich nun fragen, warum diese beiden Dateien, deren Funktion zur Zeit noch vllig offen ist, auch auf dem Server kopiert werden sollen, dann will ich Sie in Bezug auf diesen Punkt nicht mehr lnger auf die Folter spannen. Innerhalb einer Oracle-Datenbank besteht die Mglichkeit, beispielsweise mit Hilfe einer Abfrage Daten aus einer anderen Datenbank abzurufen. Diese Datenbank knnte mit seinem DBMS auf demselben oder einen vllig anderen Rechner liegen. Wie auch immer: Wenn eine Oracle-Datenbank Informationen aus einer zweiten Datenbank anfordert, dann verhlt sie sich aus Sicht dieser zweiten Datenbank wie ein gewhnlicher Client. Aus dem Grund sollte also auch auf dem Server eine funktionsfhige Client-Konfiguration vorliegen.
Grundeinstellungen via SQLNET.ORA Mit Hilfe der Konfigurationsdatei SQLNET.ORA knnen Sie ein sogenanntes Profil erstellen, mit dem Sie verschiedene Prferenzen fr die Nutzung von Net8 vorgeben knnen. Das lsst den Schluss zu, dass diese Datei im Ausnahmefall sogar fehlen knnte, wenn es berhaupt keine solcher Voreinstellungen gibt. Meistens werden Sie bei der Begutachtung vorhandener Installationen allerdings ein definiertes Profil in Form der Datei SQLNET.ORA finden.

Im Einzelnen knnen Sie mit Hilfe des Profils

: : : :

Parameter zur Namensgebung, Verschlsselungseinstellungen, Sicherheitseinstellungen, Trace- und oder Log-Einstellungen

und viele weitere Parameter festlegen. Fr kleine Installation knnen Sie die whrend der Installation als Muster kopierte Version ohne nderungen verwenden und selbst bei riesigen Netzwerken gibt es keinen zwingenden Grund fr irgendwelche Eingriffe. Beachten Sie allerdings die fett markierte Einstellung des Parameters names.default_domain, denn der Wert taucht ein paar Abstze tiefer bei der Behandlung der Dienst- bzw. Servicenamen wieder auf. Der hier eingestellte Wert sorgt fr eine automatische Qualifizierung der definierten Dienstnamen, indem er ihm automatisch zusammen mit einem Punkt angehngt wird. Mchte ein Anwender beispielsweise mit dem Dienst otto arbeiten, dann fhrt dies aufgrund des abgebildeten Parameters intern zur Anforderung otto.world.
TRACE_LEVEL_CLIENT = OFF sqlnet.authentication_services = (NTS) names.directory_path = (TNSNAMES, HOSTNAME) names.default_domain = world name.default_zone = world automatic_ipc = off
Listing 1.5: Typisches Net8-Profil

Verbindung zur Datenbank herstellen

45

Alle verfgbaren Parameter finden Sie mit einer ausfhrlichen Beschreibung wieder im Net8 Administrators Guide der Oracle-Dokumentation und dort je nach Version im Anhang B oder C. In diesem Buch finden Sie im brigen an vielen Stellen Informationen zu den Profilen mit seinen mglichen Einstellungen. Ansonsten kann ich Ihnen auch die Seiten Oracle Net8 Getting Started for Windows NT/95 empfehlen. Dort finden Sie eine zusammenhngende Beschreibung der Datei SQLNET.ORA im Anhang B Configuration File Content im Kapitel Understanding the SQLNET.ORA File.
Konfiguration der Servicenamen Alle guten Dinge sind drei, und so kommen wir abschlieend zur dritten bentigten Konfigurationsdatei. Immer wenn Sie sich mit Hilfe einer Anwendung, beispielsweise einem der reichlich mitinstallierten Werkzeuge, an eine Oracle-Datenbank anmelden mchten, dann erhalten Sie zunchst einen kleinen Dialog, in dem Sie neben einer Benutzer-Id und einem Passwort auch einen Servicenamen bzw. Dienstnamen eintragen mssen (vgl. Abb. 1.19).

Abbildung 1.19: Abfrage des Servicenamens bei einer Datenbankanmeldung

Der Service- oder auch Dienstname reprsentiert eine DBMS-Instanz nebst Datenbank, die auf irgendeinem Rechner verfgbar ist. Auf dem Client wird die Verbindung zur Datenbank also noch einmal abstrahiert, in dem Sie hier einen nahezu vllig frei whlbaren Servicenamen zur Anmeldung eingeben mssen. So wre es denkbar, dass Sie sich ber den Service DonaldDuck konkret an eine Datenbankinstanz TT23 mit der Datenbank AUSKUNFT auf einem Rechner mit der IP-Adresse 1.33.133.8 anmelden. Diese Verbindung zwischen den Dienstnamen und irgendwelchen auf irgendwelchen Rechnern laufenden Datenbankinstanzen findet in der Datei TNSNAMES.ORA statt.
GutenMorgen.world = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP) (HOST = ray_dell) (PORT = 1521) ) (CONNECT_DATA = (SID = ORCL) ) )
Listing 1.6: Beispiel der Definition eines Net8-Dienstnamens

46

Oracle erste Schritte

In dem Beispiel wird der Dienstname GutenMorgen definiert und mit der DBMSInstanz orcl auf dem Rechner ray_dell verknpft. Die Kommunikation erfolgt ber TCP/IP mit Hilfe des Ports 1521. Kommt Ihnen hierbei einiges bekannt vor? Ich habe die Zusammenhnge der drei Konfigurationsdateien LISTENER.ORA, SQLNET.ORA und TNSNAMES.ORA in der Abbildung 1.20 noch einmal zusammengefasst.
TNSNAMES.ORA
GutenMorgen.world = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP) (HOST = ray_dell) (PORT = 1521) ) (CONNECT_DATA = (SID = ORCL) ) ) names.default_domain = world

SQLNET.ORA

LISTENER.ORA
LISTENER = (ADDRESS_LIST = (ADDRESS= (PROTOCOL= TCP) (Host= ray_dell) (Port= 1521) ) ) SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (GLOBAL_DBNAME = oracle) (SID_NAME = ORCL) ) )

Abbildung 1.20: Verbindungen innerhalb der Konfigurationsdateien

Bei den Dienst- oder Servicenamen handelt es sich also wirklich um willkrliche Bezeichnungen fr konkret existierende Datenbankinstanzen. Demzufolge knnen Sie fr ein und dieselbe Datenbank auch mehrere verschiedene Dienstnamen in der Datei TNSNAMES.ORA definieren. Ein Beispiel: In der Datei TNSNAMES.ORA sind die Dienstnamen Montag, Dienstag ... Freitag definiert. Entsprechend dem Wochentag meldet sich der Benutzer mit Hilfe des zugehrigen Dienstes in der Datenbank an. Die konkreten Definitionen der Dienste in der Datei TNSNAMES.ORA legen nun fest, mit welcher Datenbank der Anwender wirklich arbeitet; vielleicht sogar immer mit derselben. Verbindung zur Starterdatenbank herstellen Wenn Sie mchten und mit einem TCP/IP-Netzwerk arbeiten, dann knnen Sie nun die Verbindung zur Starterdatenbank manuell herstellen. Hierzu finden Sie auf Ihrer CD im \NET80-Unterverzeichnis die drei soeben beschriebenen Konfigurationsdateien. Ansonsten finden Sie in den nchsten beiden Kapiteln Hinweise, wie Sie die Konfiguration mit Hilfe verschiedener Oracle-Werkzeuge vornehmen knnen. Gehen Sie zur manuellen Installation folgendermaen vor:

Verbindung zur Datenbank herstellen

47

: : :

Kopieren Sie die drei Dateien in das \NET80\ADMIN- bzw. \NETWORK\ ADMIN-Verzeichnis auf dem Datenbankserver. In der Datei SQLNET.ORA mssen Sie keine Anpassungen vornehmen. Beenden Sie alle laufenden Listenerdienste. Ermitteln Sie den Rechnernamen und ggf. die IP-Adresse des Datenbankservers. Hierzu knnen Sie auf dem Server in der Netzwerkkonfiguration nachschauen oder auch folgendermaen vorgehen: ffnen Sie auf dem Server ein MS-DOS-Fenster. Geben Sie dort den Befehl ipconfig /all (verwenden Sie ipconfig /all | more, wenn Sie nicht alles lesen knnen) ein. Notieren bzw. merken Sie sich den Rechnernamen und die IP-Adresse.

ffnen Sie auf dem Client ein MS-DOS-Fenster und berprfen Sie die Netzwerkkonfiguration. Geben Sie den Befehl ping gefolgt von dem eben ermittelten Rechnernamen (z.B. ping ray_dell) ein. Erhalten Sie ber den Rechnernamen keinen Kontakt zum Server, dann mssen Sie in den folgenden Arbeitsschritten statt des Namens die zugehrige IP-Adresse verwenden. Editieren Sie die Datei LISTENER.ORA mit Hilfe irgendeines Texteditors (z.B. NOTEPAD.EXE). Die Datei enthlt Eintrge fr die Instanz der Starterdatenbank (orcl) und die noch zu erstellende Datenbank db01. Tauschen Sie in der Datei den Namen ray_dell gegen Ihren Servernamen bzw. die eben ermittelte IP-Adresse aus. Starten Sie die Listener, indem Sie den zugehrigen Dienst wieder aktivieren. Editieren Sie die Datei TNSNAMES.ORA. Vorausschauend auf die noch zu erstellende Datenbank finden Sie auch hier schon zwei Diensteintrge (orcl.world und db01.world). Tauschen Sie jetzt den Namen ray_dell wieder gegen Ihren Servernamen bzw. dessen IP-Adresse aus. Kopieren Sie die Dateien SQLNET.ORA und TNSNAMES.ORA auf einen Client in das entsprechende \NExx\ADMIN-Unterverzeichnis. Testen Sie Ihre Konfiguration. ffnen Sie hierzu auf dem Client ein MS-DOSFenster Starten Sie das Programm TNSPING80 bzw. TNSPING (bei korrekter Installation sollte ein Pfad-Eintrag auf das \BIN-Unterverzeichnis existieren) gefolgt von dem zu berprfenden Servicenamen (z.B. TNSPING80 orcl; vgl. Abb. 1.21). Aufgrund unserer Einstellungen in der Datei SQLNET.ORA fhrt die Eingabe des Dienstnamens orcl intern immer zur Verwendung des Dienstes orcl.world.

: : : :

48

Oracle erste Schritte

Abbildung 1.21: Erfolgreicher Ping zu unserer ORCL- Instanz

Verluft der Test nicht erfolgreich, so berprfen Sie noch einmal alle durchgefhrten Arbeitsschritte. Haben Sie die Dateien an die richtigen Stellen kopiert? berprfen Sie Ihre nderungen auf Tippfehler. Ist der Datenbank- und Listenerdienst aktiv? Ein nicht erfolgreicher Test uert sich in der Anzeige einer Fehlermeldung, zum Beispiel TNS-03505: Failed to resolve name. In der Dokumentation finden Sie unter Oracle8 Error Messages eine bersicht aller vorhandenen Fehlermeldungen. Neben den Beschreibungen befinden sich hier grtenteils auch brauchbare Kochrezepte zu deren Behebung. Die TNS-Fehlermeldungen stehen dort konkret im Kapitel 25. Natrlich ist es nicht unbedingt notwendig, die Anpassungen an der Net8-Konfiguration manuell durchzufhren. Aber wie Sie an den letzten Beispielen gesehen haben, ist das bei kleinen TCP/IP-Netzwerken durchaus mglich bzw. nicht schwierig. Ansonsten haben Sie die Mglichkeit, zur Anpassung des Net8-Netzwerkes auf verschiedene Werkzeuge zurckzugreifen, die im Rahmen der Client-Installation auf Ihren Rechner kopiert werden. In den nchsten zwei Kapiteln mchte ich die Verwendung dieser beiden Werkzeuge kurz darstellen.

1.4.3

Konfiguration mit Hilfe von Net8 Easy Config

Ein Hilfsmittel zur Konfiguration des Net8-Netzwerkes heit Net8 Easy Config (Version 8: N8SW.EXE) und befindet sich blicherweise in der Programmgruppe Oracle for Windows NT. Anwendung bei einer 8er-Version Mit Hilfe dieses Programms knnen Sie auf besonders einfache Weise die Liste der Dienstnamen bearbeiten, d.h. hiermit verndern Sie lediglich die Datei TNSNAMES.ORA, die anderen beiden Konfigurationsdateien (SQLNET.ORA bzw. LISTENER.ORA) mssen Sie bei Bedarf immer noch manuell anpassen.

Verbindung zur Datenbank herstellen

49

Mit der Version 8i haben sich die Programmnamen dieser Werkzeuge alle gendert bzw. sind gar nicht mehr als eigenstndiges Programm vorhanden. Das liegt ganz einfach daran, dass die Assistenten und Hilfsmittel als JavaApplikation geliefert werden und somit besondere Klassen zur Ausfhrung des bentigten Programms existieren. Damit ist das Programm zum einen eigentlich nur geeignet, einen neuen Datenbankdienst schnell auf einem Arbeitsplatzrechner verfgbar zu machen. Zum anderen hilft das Programm natrlich auch, Tip- oder Formatfehler zu vermeiden, die sich beim manuellen Bearbeiten der Datei TNSNAMES.ORA sicherlich leicht einschleichen knnen. Im Rahmen der Installation erhalten Sie in Ihrem \NETxx\ADMIN-Unterverzeichnis eine TNSNAMES-Musterdatei mit verschiedenen Dienstnamenseintrgen. Mit Hilfe des Net&Easy-Programms, so will ich dieses Tool fortan mal nennen, wollen wir diese Datei nun so anpassen, dass wir Zugriff auf die Starterdatenbank erhalten. Hierzu mssen Sie zunchst die Listener-Konfiguration wie im vorherigen Kapitel beschrieben manuell anpassen. Anschlieend mssen Sie den Listener und die ORCL-Datenbankinstanz hochfahren. Nach dem Start des Programms (vgl. Abb. 1.22) erhalten Sie einen Dialog, mit dem Sie die Liste der Dienstnamen entsprechend Ihren Anforderungen verndern knnen. Rechts unten im Bild finden Sie eine Liste aller aktuell definierten Dienstnamen.

Abbildung 1.22: Bearbeiten der TNSNAMES.ORA mit Hilfe von Net8 Easy Config

Im mittleren Teil des Fensters knnen Sie die durchzufhrende Aktion auswhlen. Zunchst wollen wir alle nicht bentigten Dienste aus der Konfiguration entfernen. Also mssen wir die Aktion Delete auswhlen und knnen anschlieend den zu lschenden Dienst in der Liste markieren. Weiter geht es mit der Next-Schaltflche. Jetzt mssen Sie den Lschvorgang nochmals besttigen und danach erhalten Sie einen weiteren Dialog (vgl. Abb. 1.23).

50

Oracle erste Schritte

Abbildung 1.23: nderung speichern, verwerfen oder weitere Anpassungen durchfhren

An dieser Stelle knnen Sie Ihre nderungen speichern, indem Sie das Programm mit Hilfe der Schaltflche Finish beenden. Mchten Sie so wie wir allerdings noch weitere nderungen durchfhren, dann knnen Sie ber die Previous-Schaltflche wieder in das Ausgangsbild (Abb. 1.22) zurckkehren. Lschen Sie auf diese Weise alle Eintrge bis auf den Dienst mit dem Namen TcpExample. Den verbleibenden Dienst TcpExample wollen wir entsprechend unseren Bedrfnissen anpassen. Whlen Sie hierzu die Aktion Modify und markieren Sie den Dienst anschlieend in der Liste. Danach gelangen Sie nach Bettigen der NextSchaltflche zu weiteren Dialogen zum Bearbeiten der verschiedenen Diensteinstellungen. Im ersten Seite dieser Dialogfolge mssen Sie das zu verwendende Netzwerkprotokoll auswhlen. Danach gelangen Sie wieder mit Hilfe der Next-Schaltflche zur nchsten Seite, deren Aussehen sich natrlich in Abhngigkeit des gewhlten Netzwerkprotokolls unterscheidet. Wenn Sie mit TCP/IP arbeiten, dann mssen Sie hier (vgl. Abb. 1.24) den Namen bzw. die Adresse des Datenbankservers und den zu verwendenden Port eintragen. Die nchste Seite (Next-Schaltflche drcken) Dient zur Festlegung der zugehrigen Datenbankinstanz, d.h. Sie mssen hier die entsprechend SID-Bezeichnung eingeben (vgl. Abb. 1.25). Mit Hilfe der nchsten und letzten Seite knnen Sie Ihren neuen Diensteintrag testen. Im Unterschied zum Test via TNSPING80 versucht das Programm Sie jetzt allerdings mit Hilfe eines vorhandenen Benutzers an der Datenbank anzumelden, d.h. Sie werden beim Test aufgefordert einen gltigen Benutzernamen nebst Passwort einzugeben. Wenn Sie den Test fr die ORCL-Instanz durchfhren mchten, dann knnen Sie sich als Benutzer system (Passwort manager) anmelden.

Verbindung zur Datenbank herstellen

51

Abbildung 1.24: Festlegen des Datenbankservers und der Port-Nummer

Abbildung 1.25: Verknpfen des Dienstnamens mit der Datenbankinstanz

Wie Sie jetzt sicherlich schon gemerkt haben, ist die nderung des eigentlichen Dienstnamens mit Hilfe des Programms nicht mglich. Den Dienstnamen mssen Sie entweder manuell in der Datei TNSNAMES.ORA ndern oder Sie mssen den alten Dienst lschen und anschlieend mit neuen Namen wieder anlegen. Die Anlage eines neuen Dienstnamens entspricht brigens weitestgehend der soeben beim ndern beschriebenen Vorgehensweise. Neu ist, dass Sie nach Auswahl der Aktion Add New Service zunchst den neuen Dienstnamen mit Hilfe des entsprechenden Eingabefeldes festlegen mssen.

52

Oracle erste Schritte

Besonderheiten der 8i-Version In Bezug auf die Dienstnamen beinhaltet das Programm auch in der 8i-Version die gleichen Funktionalitten, sieht in einigen Details nur ein wenig anders aus. Allerdings besteht dennoch ein wesentlicher Unterschied zur Vorgngerversion, denn jetzt knnen Sie mit diesem Assistenten (vgl. Abb. 1.26) auch den Listener und wichtige Profileinstellungen konfigurieren, d.h. dieser Assistent ist nun geeignet, kleinere Netze vollstndig zu administrieren.

Abbildung 1.26: Startbild des Net8-Assistenten in der 8i-Version

Im Startbild des Assistenten knnen Sie auswhlen, welchen Dienst des Net8-Protokolls Sie konfigurieren mchten. Die dritte Auswahl fhrt zur Konfiguration der Dienstnamen und entspricht weitestgehend der Verfahrensweise der vorhing gezeigten 8er-Version. Mit Hilfe der zweiten Auswahlmglichkeit knnen Sie Profileinstellungen vornehmen und die erste Auswahl ermglicht die Konfiguration des Listeners, wobei ich die Arbeitsweise des Assistenten an diesem Beispiel kurz demonstrieren mchte. Mit Hilfe der Weiter-Schaltflche gelangen Sie auf die zweite Seite, in der Sie whlen knnen, ob Sie einen neuen Dienst erstellen oder einen vorhandenen Dienst bearbeiten, lschen oder umbenennen mchten. Sofern Sie die Musterdatei LISTENER. ORA in das \NETWORK\ADMIN-Verzeichnis kopiert haben, knnen Sie sich hier einmal fr das Bearbeiten des Dienstes entscheiden, und sich anschlieend die Darstellung der verschiedenen Einstellungen einmal anschauen. In dieser Datei ist lediglich ein Listener definiert, der genau wie dieser Prozess nmlich LISTENER heit, so dass Sie in der auf der dritten Seite angezeigten Auswahlbox auch nur diesen Namen whlen knnen. Auf der nun folgenden Seite knnen Sie die gewnschten Netzwerkprotokolle auswhlen (vgl. Abb. 1.27) und in den darauffolgenden Seiten mssen Sie je nach ausgewhltem Protokoll weitere Einstellungen, beispielsweise die Port-Nummer bei TCP, vornehmen.

Verbindung zur Datenbank herstellen

53

Abbildung 1.27: Auswahl der Protokolle fr die Listenerkonfiguration

1.4.4

Oracle-Networking mit Hilfe des Net8 Assistant

Bis einschlielich der Version 7 des Oracle-Servers gab es bisher auch bei NTArbeitsplatzrechnern immer einen Grund, sich neben dem NT-Client auch den alten 16-Bit Windows-Client zu installieren, da im Rahmen dieser Installation ein Werkzeug, der Oracle Network Manager, zur komfortablen Konfiguration des SQL*Nets installiert wurde. Mit Hilfe des Oracle Network Managers konnte man nicht nur die Dienstnamen verwalten, sondern das Programm konnte weiterhin alle bentigten Parameterdateien erzeugen. Heute ist die Installation des Windows-Clients zumindest aus diesem Grund nicht mehr notwendig, denn mittlerweile wird im Rahmen des NT-Clients das Programm Oracle Net8 Assistant installiert, mit dem ebenfalls alle bentigten Konfigurationsdateien erstellt werden knnen, wobei hierbei vor allem auch alle neuen Features des Net8-Netzwerkes untersttzt werden. Standardmig finden Sie den Oracle Net8 Assistant in der Programmgruppe Oracle for Windows NT. Nach dem Start des Programms erhalten Sie links im Bild (vgl. Abb. 1.28) eine bersicht aller vorhandenen Konfigurationseinstellungen. Wenn Sie mit der Maus auf einen dieser dargestellten Konfigurationsparameter klicken, dann erhalten Sie im rechten Arbeitsfenster einen hierzu passenden Dialog. Die Abbildung 1.28 zeigt den Dialog den Sie erhalten, wenn Sie in der Liste die Konfiguration Profile markieren. Dieses Programm ist bei den Versionen 8 bzw. 8i im brigen nahezu funktionskompatibel und sieht in der 8i-Varianten wie Sie der Abbildung 1.29 entnehmen knnen nur anders aus. Aus diesem Grund ist die Behandlung dieses Werkzeugs diesmal zusammengefasst, und nur die Abbildungen kommen zum Teil doppelt vor.

54

Oracle erste Schritte

Abbildung 1.28: Profilerstellung mit Hilfe des Oracle Net8 Assistant

Abbildung 1.29: Oracle Net8 Assistant in der 8i-Version

Verbindung zur Datenbank herstellen

55

Wie Sie schon wissen, entspricht das Profile den Einstellungen aus der Datei SQLNET.ORA. Als Symbol wird kein Ordner angezeigt, da es immer nur ein Profil gibt. Die anderen Konfigurationen knnen mehrfach auftreten (z.B. mehrere Service- bzw. Dienstnamen oder mehrere Listener), weshalb Sie hierfr entsprechende Ordnereintrge finden. Zur grundstzlichen Bedienung des Programms mchte ich an dieser Stelle auch nicht viele weitere Worte verlieren. Ich denke, dass man das Programm weitestgehend intuitiv bedienen kann. Ein weiterer Unterschied zu dem im vorherigen Kapitel beschriebenen Net&EasyProgramm ist auch, dass Sie mit Hilfe des Oracle Net8 Assistant Konfigurationsdateien in jedem erreichbaren Verzeichnis bearbeiten knnen. Standardmig ffnet das Programm die im Verzeichnis \NETxx\ADMIN gespeicherten Konfigurationen, allerdings knnen Sie mit Hilfe der File- bzw. Datei-Meneintrage das aktuelle Verzeichnis wechseln oder geladene Konfigurationen in einem anderen Verzeichnis speichern bzw. von dort laden. Im weiteren Verlauf dieses Kapitels soll nun zum wiederholten Male eine Verbindung zu unserer Starterdatenbank hergestellt werden, wobei diesmal logischerweise der Oracle Net8 Assistant verwendet wird. Beginnen wir mit dem Profil, also mit den Einstellungen in der Datei SQLNET.ORA. Obwohl wir hier nichts ndern wollen bzw. mssen, knnen Sie sich die verschiedenen Profileinstellungen ja einmal anschauen, indem Sie mit der Maus auf den entsprechenden Eintrag in der Liste klicken (vgl. Abb. 1.29 oder Abb. 1.28). Standardmig zeigt der Net8-Assistent fr das Profil den Naming-Dialog bzw. die Namensgebung an, der insgesamt drei Registerkrtchen enthlt. Mit Hilfe des oberhalb dargestellten Kombinationsfeldes knnen Sie weitere Konfigurationsdialoge fr das Profil einblenden. Anpassen mssen Sie natrlich wieder die Dienstnamen. Klicken Sie hierzu zunchst auf das zugehrige Ordnersymbol in der Liste, so dass anschlieend alle vordefinierten Servicenamen angezeigt werden (vgl. Abb. 1.30 und Abb.1.31). hnlich der Vorgehensweise bei der Konfiguration mit Hilfe von Net&Easy knnen Sie zunchst alle nicht bentigten Dienstnamen lschen. Markieren Sie hierzu Sie den entsprechenden Dienst in der Liste und lschen Sie Ihn entweder mit Hilfe der roten X-Schaltflche oder Sie verwenden den entsprechenden Eintrag aus dem Edit- bzw. Bearbeiten-Men. Das Anlegen eines neuen Dienstes geht genauso schnell. Mit Hilfe des Edit- bzw. Bearbeiten-Mens oder durch Klicken auf der grnen +-Schaltflche knnen Sie einen neuen Dienstnamen erstellen. Anschlieend erhalten Sie die schon bekannten Seiten des Net&Easy Assistenten zum Erstellen neuer Dienstseiten. Fr Anwender der 8er-Version ist eigentlich nur die Mglichkeit zur Konfiguration der Listenersteuerung wirklich neu. Klicken Sie auf das Ordnersymbol des Listeners und fgen Sie mit Hilfe der entsprechenden Schaltflche oder des zugehrigen Filebzw. Bearbeiten-Meneintrags eine neue Listenerkonfiguration in die Liste ein. Zunchst erhalten Sie einen Dialog, in dem Sie den Namen des Listeners eintragen mssen. Standardmig heit der erste und oftmals einzige Horchdienst schlicht und einfach LISTENER (vgl. Abb. 1.32).

56

Oracle erste Schritte

Abbildung 1.30: Bearbeiten der Dienstnamen mit dem Net8-Assistenten

Abbildung 1.31: Bearbeiten der Dienstnamen mit dem Net8-Assistenten unter 8i

Verbindung zur Datenbank herstellen

57

Abbildung 1.32: Eingabe des neuen Listenernamens

Wenn Sie den Dialog mit der OK-Schaltflche beenden, dann erscheint der neue Eintrag in der Liste und Sie haben die Mglichkeit, die verschiedenen Konfigurationseinstellungen vorzunehmen. Whlen Sie mit Hilfe des Kombinationsfeldes zunchst den Dialog Listening Locations bzw. Listener Adressen (vgl. Abb. 1.33 und Abb. 1.34) aus. Anschlieend erhalten Sie einen Dialog, mit dem Sie die abzuhrenden Protokolle nebst weiteren protokollabhngigen Einstellungen vornehmen knnen. Die hier spezifizierten Protokolle und Einstellungen finden Sie spter in der Konfigurationsfdatei als Adress-Parameter-Liste hinter dem Schlsselwort LISTENER. Mit Hilfe der Schaltflche Add Address knnen Sie weitere Protokolle hinzufgen, wobei Sie fr jedes neue Protokoll ein weiteres Registerkrtchen erhalten. Bei unserer manuellen Konfiguration hatten wir den Listener an zwei Ports lauschen lassen. Fr diesen zweiten Port mssen Sie ebenfalls ein zweites Registerkrtchen anlegen, indem Sie den zweiten Port 1526 eintragen.

Abbildung 1.33: Abhrdienste des neuen Listeners konfigurieren

58

Oracle erste Schritte

Abbildung 1.34: Konfiguration der Listener-Adressen beim 8i-Assistenten

Neben den Protokollen mssen Sie auch noch festlegen, fr welche Datenbanken der Listener das Netzwerk abhorchen soll. Whlen Sie hierzu in dem oberen Kombinationsfeld den Eintrag Database Services bzw. Datenbankdienste, wodurch Sie den zugehrigen Konfigurationsschirm erhalten (vgl. Abb. 1.35 bzw. Abb. 1.36).

Verbindung zur Datenbank herstellen

59

Abbildung 1.35: Eintragen der Datenbanken, fr die das Netz abgehorcht werden

Abbildung 1.36: Einstellung der Datenbankdienste beim 8i-Assistenten

60

Oracle erste Schritte

Tragen Sie in dem Bild den System-Identifer (SID) der Datenbankintanz (z.B. orcl) und den Datenbanknamen (z.B. oracle) ein. Erstellen Sie anschlieend mit Hilfe der Schaltflche Add Database bzw. Datenbank hinzufgen eine zweite Registerkarte fr die noch zu erstellende Datenbank (SID = db01, Name = datab01). Zum Schluss mssen Sie Ihre Konfiguration noch mit Hilfe des File- bzw. DateiMens speichern, wodurch die Konfigurationsdateien in dem gewhlten Verzeichnis erstellt bzw. aktualisiert werden.

1.4.5

Ausblick

Mit Hilfe der letzten Kapitel haben Sie (hoffentlich) gesehen, dass es zumindest auf den zweiten Blick gar nicht so schwierig ist, eine Datenbankverbindung mit Hilfe von Net8 zu konfigurieren. Ich denke, dass wenn man die Zusammenhnge in etwa kennt, dann ist es mit Hilfe der Assistenten gar nicht so schwierig, die Konfiguration auf die bentigten Belage zuzuschneiden. In diesem letzten Kapitel zu dem Thema Oracle-Networking mchte ich nun noch einige weitere Konfigurationsmglichkeiten, die Ihnen die aktuelle Version von Net8 bietet, kurz ansprechen und damit diesen Themenkomplex abrunden. Verbindung via Host-Naming Hierbei handelt es sich um ein neues Verfahren, das allerdings ausschlielich fr TCP/IP-Netzwerke verfgbar ist. Konkret bietet das Verfahren die Mglichkeit, die Verbindung zur Datenbank ber das installierte Verfahren zur Namensauflsung herzustellen, indem als Servicename der Name des Datenbankrechners verwendet wird. Hierbei ist es gleichgltig, ob die Namensauflsung im IP-Netzwerk mit Hilfe irgendwelcher Namensserver oder mit Hilfe simpler Hostnamendateien durchgefhrt wird. Wie schon gesagt, muss bei dieser Methode kein spezieller Dienstname definiert werden, d.h. die Erstellung bzw. Anpassung der Datei TNSNAMES.ORA ist nicht notwendig. Allerdings muss das Verfahren im verwendeten Profil aktiviert sein, indem der Parameter names.directory_path den Wert HOSTNAME erhlt:
names.directory_path = (TNSNAMES, HOSTNAME)

Weiterhin bentigten Sie in der Konfiguration des Listeners eine entsprechende Einstellung, die den Datenbanknamen mit der zugehrigen Datenbankinstanz verbindet, was allerdings, wie Sie schon wissen, quasi Listener-Standard ist:
(SID_DESC = (GLOBAL_DBNAME = oracle) (SID_NAME = ORCL))

Was jetzt noch fehlt, ist ein Hostname des Datenbankservers, der dem Datenbanknamen entspricht. Auch wenn Sie Ihren Server nicht ORACLE taufen mchten, so ist dieser bentigte Name zumindestens als sogenannter Aliasname schnell erstellt, indem Sie einen entsprechenden Eintrag in Ihrem Netzwerknamensdienst vornehmen. Sollten Sie keinen speziellen Namensdienst haben, dann suchen Sie einfach mal nach der Datei HOSTS, denn diese Datei stellt einen Minimalnamensdienst zur Verfgung. Tragen Sie in der Datei die IP-Adresse des Datenbankservers

Verbindung zur Datenbank herstellen

61

gefolgt von dem zugehrigen Datenbanknamen ein und schon knnen Sie sich ber den Hostnamen an die Datenbank anmelden. Das Verfahren funktioniert brigens auch, wenn auf einem Datenbankserver mehrere Instanzen bzw. Datenbanken aktiv sind. In dem Fall mssen Sie einfach fr alle Datenbanken entsprechende Aliasnamen vergeben. Oracle Names Hierbei handelt es sich im Prinzip um eine Erweiterung des eben beschriebenen einfachen Verfahrens des Host-Naming. Konkret wird bei dieser Methode ein zentraler Dienst im Netzwerk bereitgestellt, der die Dienstnamen den entsprechenden Rechneradressen, wodurch sich der Client mit der Datenbank verbinden kann. Ein wichtige Funktionalitt dieser Methode ist beispielsweise die Mglichkeit der dynamischen Registrierung von Servern whrend des laufenden Betriebes. Die bei dieser Methode notwendige Konfiguration knnen Sie mit Hilfe des Oracle Net8 Assistant durchfhren. Genaueres zu der Methode und deren Konfiguration finden Sie in der Dokumentation im Buch Net8 Administrators Guide. Oracle Connection Manager Dieses Feature wurde ebenfalls neu mit der Version 8 bereitgestellt und bietet im Wesentlichen folgende Funktionalitten:

Verbindungsbndelung Der Connection Manager ermglicht die logische Zusammenfassung der Verbindungen mehrerer Client-Sitzungen, die mit demselben Server kommunizieren. In dem Fall kommuniziert der Server nur noch mit diesem zentralen Knoten, der die einzelnen Anforderungen sammelt bzw. die erhalten Ergebnisse verteilt. Hierdurch knnen die bentigten Netzwerkressourcen reduziert bzw. die Performance gesteigert werden. Zugriffskontrolle Durch die Definition verschiedener Regeln besteht die Mglichkeit zu definieren, unter welchen Bedingungen ein Client auf einen Server bzw. eine Datenbank zugreifen darf. Wie Sie im Verlauf dieses Kapitels sicherlich schon gemerkt haben, reicht normalerweise die Kenntnis der IP-Adresse des Datenbankservers aus, um in der Lage zu sein, zumindest eine Verbindung zum DBMS herzustellen. Zwar bentigt man immer noch eine Benutzer-ID und ein Passwort, aber die Verbindung ist schon einmal hergestellt. Der Connection-Manager kann hier eine Art Firewall-Funktion wahrnehmen, indem er verhindert, dass nicht explizit zugelassene Clients eine Verbindung aufnehmen knnen.

62

Oracle erste Schritte

1.5

Erstellen einer Datenbank

In diesem Kapitel mchte ich Ihnen zeigen, wie man in Oracle eigene Datenbanken erstellen kann. Allein an der Tatsache, dass es fr dieses Vorgang ein eigenes Kapitel gibt, knnen Sie vielleicht erahnen, dass dieser Prozess im Vergleich zu anderen Datenbank-Managementsystemen ein wenig aufwendiger ist. Es gibt Datenbanksysteme (z.B. SYBASE oder MS SQL-Server), da handelt es sich bei der Anweisung zur Anlage einer Datenbank um einen Befehl wie jeden anderen auch, d.h. man baut eine Verbindung zum DBMS auf und gibt anschlieend einen Befehl der Art create database mit irgendwelchen Parametern ein. Eine solche Vorgehensweise funktioniert in der Regel beim einem DBMS, das nicht nur fr eine, sondern fr alle auf dem Rechner laufenden Datenbank zustndig ist. Nun haben Sie in den einfhrenden Kapiteln aber schon gesehen, dass sich Oracle gerade in dieser Architektur von dem einen oder anderen Konkurrenzprodukt unterscheidet. Fr jede Datenbank existiert auch ein eigenes DBMS, also steht vor der Anlage der Datenbank die Erzeugung einer neuer DBMS-Instanz auf dem Aufgabenzettel. Konkret gibt es fr die Anlage einer DBMS-Instanz und der Erstellung der Datenbank wie immer mehrere verschiedene Verfahrensweisen; die Bandbreite der mglichen Wege reicht je nach verwendetem Betriebssystem von do it yourself bis hin zur vllig automatischen Datenbankgenerierung. Dabei werde ich das vollautomatische Verfahren, das beispielsweise unter Windows-NT mglich ist, nur kurz beschreiben. Das manuelle Verfahren ist wesentlich interessanter. Zum einen ist es leicht auf alle verfgbaren Betriebsplattformen bertragbar, bietet viele ntzliche Informationen ber Oracle und entspricht zum anderen der zur Zeit gngigen Verfahrenspraxis. Zumindest ist mir bisher noch kein Anwender begegnet, bei dem Datenbanksysteme von irgendwelchen Programmen abstrakt und vollautomatisch nach manueller Parametereingabe generiert wurden. Stattdessen wurden zunchst alle zur Generierung bentigten Skripte und Parameterdateien erstellt, mit deren Hilfe die eigentliche Datenbankerstellung in einem zweiten Schritt erfolgte. Diese vielleicht altmodisch wirkende Vorgehensweise hat jedoch den Vorteil, dass die Datenbankerstellung (z.B. auf einem anderen Rechner) jederzeit leicht wiederholbar ist. Im brigen ist das manuelle Verfahren in der aktuellen Oracle-Version gar nicht mehr so ganz manuell, denn die bentigte Skripte knnen mit Hilfe eines Assistenten erstellt werden. Fr welches Verfahren Sie sich auch entscheiden: in jedem Fall bentigen Sie bestimmte Informationen ber die Struktur einer Oracle-Datenbank, d.h. an dem folgenden Kapitel fhrt so oder so kein Weg vorbei.

1.5.1

Struktur einer Oracle-Datenbank

Wie Sie wissen, wird in Oracle eine Datenbank als logische Einheit einer DBMSInstanz und den eigentlichen Datenbankdateien gebildet. Diese Instanz vereint alle fr den Betrieb der Datenbank bentigten Prozesse nebst Hauptspeicherbereiche und holt seine Konfiguration, z.B. die Gre der SGA oder den Namen der Datenbank beim Starten aus einer speziellen Parameterdatei (vgl. Abb. 1.37) mit

Erstellen einer Datenbank

63

dem Namen INITSID.ORA, wobei Sie den Platzhalter SID durch den konkreten System-Identifer des DBMS ersetzen mssen. Wenn Sie die Starterdatenbank (SID=orcl) installiert haben, dann finden Sie in Ihrem \DATABASE-Unterverzeichnis beispielsweise die zugehrige Konfigurationsdatei INITORCL.ORA. Die Datenbank selbst besteht aus mindestens einer physikalischen Datei, in der die zu speichernden Daten mit Hilfe von Tabellen oder andere Datenbankobjekte abgelegt werden. Wie Sie schon wissen, liegt zwischen der physikalischen Datei und der Tabelle das logische Tablespace-Konstrukt und somit folgt aus dem bisher Gesagten, dass jede Datenbank zumindest auch einen Tablespace besitzen muss. Dieser trgt den Namen SYSTEM und wird beim Anlegen der Datenbank automatisch erzeugt. Zustzlich bentigt die Datenbank mindestens zwei Protokolldateien. Oftmals werden Sie in dem Zusammenhang die Bezeichnungen redo log oder redo log Dateien finden. Diese Log-Dateien werden bentigt, um die Datenbank beispielsweise nach einem Systemzusammenbruch (Server wird ausgeschaltet) wiederherzustellen. Konkret werden in den redo log Dateien alle nderungen mit Hilfe des LGWR-Prozesses (vgl. Kapitel 1.1.2) protokolliert. Genauer betrachtet werden in diesen Dateien alle fertiggestellten nderungstransaktionen in der Form von Low Level-nderungsoperationen festgehalten. Erst wenn die nderungen im redo log protokolliert wurden, wird eine Transaktion als endgltig erledigt markiert und das Zurckschreiben der genderten Daten aus der SGA in die Datendatei erfolgt vielleicht sogar noch etwas spter. Wird die Datenbank nach einem versehentlichen Ausschalten oder einem Stromausfall wieder hochgefahren, dann wird die Datenkonsistenz mit Hilfe dieser Log-Dateien wieder hergestellt. Der Prozess des Hochfahrens kann somit schon einmal eine Weile dauern, wenn das notwendige Recovery der Daten entsprechend aufwendig ist. Whrend des Datenbankbetriebs wachsen die einzelnen Log-Dateien allerdings nicht ins Unendliche, sondern sie werden zyklisch genutzt und somit in regelmigen Abstnden immer wieder berschrieben. Damit schtzen die Log-Dateien zunchst auch nur vor einem Systemcrash, beispielsweise als Folge unbezahlter Stromrechnungen. Bei anderen Fehlern, beispielsweise dem Datenbankausfall wegen defekter Festplatten, mssen Sie zunchst auf die letzte Datensicherung zurckgreifen. Htte man nun noch alle Log-Eintrge, die seit der letzten Vollsicherung erstellt wurden, dann knnte man sich einen Wiederherstellungsprozess bis zu jedem beliebigen nachfolgenden Zeitpunkt vorstellen, denn wie gesagt, die LogDateien reprsentieren jede fertiggestellte Transaktion durch die zugehrigen nderungsdaten. Damit dies nicht nur ein Wunsch bleibt, besteht die Mglichkeit, die einzelnen Log-Dateien vor dem berschreiben zu kopieren. Hierzu mssen Sie fr Ihre Datenbankinstanz den ARCH-Prozess (engl. Archiver) aktivieren, der fr die Archivierung voller Log-Dateien zustndig ist. So, eigentlich wollte ich nur anmerken, dass Sie bei einer Oracle-Datenbank mindestens immer zwei Log-Dateien finden, aber Sie sehen ja selbst, wie schnell man bei diesem komplexen aber auch interessanten Thema vom Wege abkommt. Wenn Sie weitergehende Informationen zu diesem Themenkomplex suchen, empfehle

64

Oracle erste Schritte

ich Ihnen neben den originalen Handbchern ein Buch, das sich hauptschlich mit Themen aus dem Alltag eines Datenbankadministrators beschftigt. Dort sollten weiterfhrende Dinge wie Konzepte zur Sicherung und Wiederherstellung von Datenbanken, Online-Sicherungen oder den 24 Stundenbetrieb einer Datenbank hinreichend behandelt werden. Zurck zu unserer Datenbankstruktur. Neben der Konfigurationsdatei fr das DBMS, der eigentlichen Datendatei und den beiden Log-Dateien besitzt jede Oracle-Datenbank noch mindestens eine sogenannte Kontrolldatei (engl.. Control File). Diese Kontrolldatei stellt die Achillesverse Ihres Datenbanksystems dar, denn in ihr werden Informationen ber die zur Datenbank gehrenden Dateien gespeichert. Ist diese Kontrolldatei zerstrt bzw. weg, dann kann die Datenbank, wenn berhaupt, nur noch mit viel Glck wiederhergestellt werden. Das ist auch der Grund, warum Oracle grundstzlich die Anlage von mehreren (wenigstens zwei) Kontrolldateien empfiehlt, die mglichst auch auf unterschiedlichen Festplatten gespeichert werden sollen. Mehr zum Umgang mit diesen Kontrolldateien finden Sie in der Oracle-Dokumentation, beispielsweise im Buch Server Administrators Guide im Kapitel Managing Control Files.

DBMS SID = DB01

TABLESPACE SYSTEM ROLLBACK SYSTEM

Konfguration (INITDB01.ORA)

Datei (datafile)

Log-Datei (redo log)

Kontrolldatei (controlfile)

Abbildung 1.37: Physische Struktur einer Oracle-Datenbank

Wie Sie in der Abbildung 1.37 erkennen knnen, wird in dem Datenfile neben dem SYSTEM-Tablespace auch noch ein sogenanntes Rollback-Segment, ebenfalls mit dem Namen SYSTEM, angelegt. Rollback-Segmente Jede Datenbank enthlt mindestens ein sogenanntes Rollback-Segment. In einem solchen Rollback-Segment werden die whrend einer Transaktion genderten Daten protokolliert. Diese Protokolle werden fr das Zurcksetzen von Transaktion, dem Recovery beim ffnen der Datenbank oder auch fr die Bereitstellung lesekonsistenter Abfragen bentigt. Oracle zeigt genderte Daten erst nach dem

Erstellen einer Datenbank

65

Beenden und Freigeben (commit) einer Transaktion. Whrend der Transaktion erhalten andere Abfragen die Daten in dem Zustand vor der nderung, d.h. die Werte werden bei Bedarf mit Hilfe der Rollback-Segmente geliefert. Ohne Rollback-Segment wre eine Oracle-Datenbank eine reine Leseveranstaltung, deshalb wird im Rahmen der Datenbankanlage automatisch ein Rollback-Segment mit dem Namen SYSTEM im gleichnamigen Tablespace angelegt. Das Rollback-Segment mu seinerseits aus mindestens zwei Erweiterungen (Extends) bestehen, die im Rahmen der Transaktionen sequentiell beschrieben bzw. im Rahmen neuer Transaktionen immer wieder berschrieben werden. Die Gre des Rollback-Segments muss hierbei so dimensioniert werden, dass die nderungsdaten der grten bentigten Transaktion dort hineinpassen, wobei es prinzipiell mglich ist, die nderungen einer Transaktion gezielt einem speziellen (besonders groen) Rollback-Segment zuzuordnen. Standardmig werden die freien Rollback-Segemente automatisch zugeordnet, so dass vor allem im Mehrbenutzerbetrieb viele Transaktionen um die Gunst bzw. den Platz der Rollback-Segmente ringen. Die Segmente selbst ringen ggf. konkurrierend mit anderen Objekten um Platz im Tablespace. Aus diesen Grnden empfiehlt Oracle zum einen die Anlage eigener Rollback-Segmente, mglichst ein einem Tablespace, der auf einer eigenen Datei basiert. Nachdem Sie nun die minimale physische Struktur einer Oracle-Datenbank kennen, knnen wir im nchsten Abschnitt damit beginnen, endlich unsere eigene Datenbank anzulegen. Hierbei werden sie die eben kennen gelernten Dateien erstellen oder deren Namen nebst Zugriffspfad festlegen mssen.

1.5.2

Das manuelle Verfahren

In Oracle erfolgt die Anlage einer neuen Datenbank im Prinzip in folgenden Schritten:

: : :

Erstellen der Konfigurationsdatei INITxxxx.ORA entsprechend dem gewnschten System Identifer. Erstellen der neuen Datenbankinstanz. Anlegen der neuen Datenbank. Abspielen verschiedener Standardskripte, die in der neuen (noch leeren) Datenbank verschiedene Systemobjekte anlegen.

Nach Durchfhrung dieser einzelnen Arbeitsschritte sind Sie im Besitz einer neuen Datenbank. Anschlieend sind in der Regel noch weitere Aktivitten, z.B. die Erweiterung des Net8-Netzwerkes oder die Anlage weiterer Tablespaces oder Datenbankdateien, notwendig, was aber genau genommen mit der eigentlichen Datenbankerzeugung gar nichts zu tun hat. Im Folgenden wollen wir die Datenbankinstanz db01 und die zugehrige Datenbank datenb01 erstellen. Alle hierzu bentigten Dateien und Skripte finden Sie auf der Begleit-CD im \DB01-Unterverzeichnis.

66

Oracle erste Schritte

Erstellen der Konfigurationsdatei Da es sich bei dieser Konfigurationsdatei um eine gewhnliche Textdatei handelt, kann sie folglich mit jedem beliebigen Texteditor erstellt werden. Selten werden Sie dabei in der Praxis die Arbeit mit einer leeren Datei beginnen, sondern die neue Konfiguration entsteht aus einer Kopie einer schon vorhandenen Datenbank. Selbst wenn Sie gerade die erste Datenbank erstellen, dann finden Sie in Ihrem \DATABASE-Unterverzeichnis die Datei INITORCL.ORA, so dass Sie die Konfigurationsdatei der Starterdatenbank als Muster verwenden knnen. Diese Musterdatei besteht hauptschlich aus Kommentaren, denn neben den wirklichen Anmerkungen in der Datei sind auch die meisten Parameter mit Hilfe des Gatterzeichens (#) auskommentiert. Trotzdem erhalten Sie hierdurch eine Vorstellung ber die wichtigsten Konfigurationsparameter, deren genaue Bedeutung Sie in der Oracle-Dokumentation finden. Folgen Sie im Buch Server Reference bzw. Oracle8i Reference den Eintrag 1 Initialization Parameters und dort weiter zum Abschnitt Parameter Description. Hier finden Sie eine alphabetische Liste aller vorhandenen Konfigurationsparameter zusammen mit der zugehrigen Beschreibung. Im Server Administrators Guide finden Sie im Abschnitt Chapter 2 Creating an Oracle Database im Kapitel Parameters ebenfalls eine Beschreibung der wichtigsten Konfigurationsmglichkeiten. Falls Sie die Musterdatei INITORCL.ORA nicht besitzen, so finden Sie die Datei brigens auf der Begleit-CD im \ORCL-Unterverzeichnis. In unserem Beispiel hat die Konfigurationsdatei den Namen INITDB01.ORA und lediglich folgenden Inhalt:
db_name=datenb01 db_files = 100 control_files=(E:\ORANT\DATABASE\db01\ctl1db01.ora,E:\ORANT\DATABASE\db01\ctl2db01.ora) remote_login_passwordfile = shared #rollback_segments = (RB0, RB1)
Listing 1.7: Minimum einer Instanz-Konfiguration

db_name Mit Hilfe dieses Parameters bestimmen Sie den maximal achtstelligen Namen der Datenbank. Gltige Zeichen sind vor allem Buchstaben, Ziffern und der Unterstrich (_). Zwischen Gro- und Kleinschreibung wird nicht unterschieden. Der hier spezifizierte Name muss auch beim spteren Anlegen der Datenbank verwendet werden. db_files Maximale Anzahl der mglichen Datenbankdateien. Sowohl der Standard- als auch der Maximalwert fr dieses Parameter ist abhngig vom vorhandenen Betriebssystem. Wir whlen den Wert von 100 (das sollte erst einmal reichen) und mssen diesen Wert spter beim Anlegen der Datenbank noch einmal vorgeben.

Erstellen einer Datenbank

67

control_files Legen Sie hier den Pfad und Dateinamen der Kontrolldatei(en) fest. Wenn Sie, wie empfohlen, wenigstens zwei oder mehr Kontrolldateien verwenden, dann mssen Sie die einzelnen Dateinamen durch Komma trennen und das Ganze wie in meinem Beispiel in Klammern setzen. Die genaue Spezifizierung der Dateinamen hngt natrlich vom jeweiligen Betriebssystem ab. remote_login_passwordfile = shared Dieser Parameter legt fest, ob zur berprfung der Anmeldeberechtigung eines Datenbankadministrators eine spezielle Passwortdatei angelegt werden soll. Die Passwortdatei wird standardmig im \DATABASE-Unterverzeichnis mit dem Namen PWDSID.ORA erstellt, wobei SID wieder ein Platzhalter der entsprechenden Instanz darstellt. Mehr zum Thema der Identifizierung von Administratoren finden Sie in den Oracle-Unterlagen im Buch Server Administrator's Guide, beispielsweise im Kapitel The Oracle Database Administrator. rollback_segments Mit dem Parameter legen Sie die zu verwendenden Rollback-Segmente fest. Dies ist wichtig, wenn Sie neben dem SYSTEM-Tablespace weitere Bereiche definieren und verwenden mchten. Da diese Rollback-Segmente beim Anlegen der Datenbank jedoch noch nicht definiert sind, ist es wichtig den Parameter zunchst einmal auszukommentieren. Schalten Sie ihn erst ein, nachdem die gesamte Datenbank erstellt wurde. Damit er aktiv wird, mssen Sie die Instanz runter, und anschlieend wieder hochfahren.

Warum hat diese Konfiguration im Vergleich zur Starterdatenbank oder im Vergleich zu real existierenden Versionen so wenige Parameter? Zum einen stellen Sie beim Lesen der Dokumentation fest, dass fr die allermeisten Parameter ein fester oder betriebssystemabhngiger Standardwert existiert, der beim Starten der Datenbankinstanz verwendet wird, sofern in der Konfigurationsdatei nichts anderes spezifiziert wurde. Zum anderen finden Sie in der Musterdatei INITORCL.ORA die wirklich interessanten und wichtigsten Parameter, deren einzelne Bedeutung Sie in einer ruhigen Stunde durchaus mal nachschlagen sollten, sofern Sie zuknftig hufiger Datenbanken erstellen mssen. Auf der anderen Seite mchte ich hier natrlich aufzeigen, worauf es wirklich ankommt und das erkennt man meistens am besten, wenn mal alles berflssige bzw. Unntige einfach mal weglsst. Erstellen der neuen Datenbankinstanz Nachdem wir nun unsere neue Konfigurationsdatei fr das System DB01 besitzen, knnen wir die zugehrige Instanz auf unserem Rechner starten. Wie das genau geht, hngt allerdings stark vom jeweiligen Betriebssystem ab. Fr Windows NT erhalten Sie mit der Installation das Programm ORADIM80.EXE (Instanzen-Manager), mit dem eine neue Datenbankinstanz erstellen bzw. starten knnen. Das Programm knnen Sie zum Beispiel in einem MS-DOS-Fenster zusammen mit allen bentigten Parametern starten:

68

Oracle erste Schritte

ORADIM80 -NEW -SID SID [-INTPWD INTERNAL_PWD] [-SRVC SRVCNAME] [-STARTMODE AUTO, MANUAL][-PFILE FILENAME]

Unter 8i heit das Programm einfach nur ORADIM.EXE, und wird ansonsten allerdings vllig identisch verwendet.

: :

SID System Identifer der neuen Instanz. Entsprechend dem hinteren Teil der Konfigurationsdatei mssen Sie in unserem Beispiel db01 als SID vorgeben. INTERNAL_PWD Passwort fr die Administrator-ID internal. Whrend der Anlage der neuen Datenbankinstanz wird hierfr eine Passwortdatei angelegt. Diese Datei befindet sich im \DATABASE-Unterverzeichnis und hat den Namen PWDSID.ORA, wobei SID wieder durch den konkreten System Identifer ersetzt wird. SRVCNAME Wie Sie schon wissen, besteht unter Windows-NT die Mglichkeit, die Datenbankinstanz mit Hilfe eines entsprechenden Diensteintrags zu administrieren. Mit Hilfe dieses Parameters knnen Sie den Namen dieses Dienstes vorgeben. Standardmig heit der neue Dienst OracleServiceSID, wobei SID wieder fr den System Identifer (z.B. DB01) der neuen Instanz steht. AUTO, MANUAL Legt die Startart des neuen Dienstes fest. Auf einem echten Datenbankserver wre AUTO wahrscheinlich die richtige Wahl. Auf meinem NT-Notebook gefllt mir MANUAL besser. Auerdem werden wir im weiteren Verlauf wieder eine Batchdatei zum Starten der Datenbank erstellen. Beachten Sie aber, dass der Instanzen-Manager den Service OracleStartSID zum Starten der Datenbank nur dann einrichtet, wenn Sie den Wert AUTO verwenden. FILENAME Pfad und Name der Konfigurationsdatei INITSID.ORA. Standardmig erwartet das Programm die Konfigurationsdatei im \DATABASE-Unterverzeichnis unter der eben beschriebenen Namenskonvention, so dass Sie den Parameter in dem Fall auch weglassen knnen.

In meinem Beispiel soll die Datenbank db01 angelegt werden. Die Konfigurationsdatei INITDB01.ORA befindet sich im Verzeichnis E:\ORANT\DATABASE\DB01, so dass die neue Instanz folgendermaen erstellt werden kann:
oradim80 -new -sid db01 -intpwd oracle -startmode auto -pfile E:\ORANT\database\db01\initdb01.ora

Das Programm arbeitet stillschweigend, legt den neuen Dienst und die Passwortdatei an. Eventuelle Fehler oder Erfolgsmeldungen mssen Sie der zugehrigen LogDatei ORADIMxx.LOG entnehmen, die Sie standardmig im \RDBMSxx-Unterverzeichnis finden. Sofern beim Programmaufruf und in der Konfigurationsdatei

Erstellen einer Datenbank

69

keine Tippfehler vorliegen, dann sollten Sie in der Log-Datei lediglich eine Erfolgsmeldung ber die Anlage der neuen Instanz vorfinden. Nach dem Einrichten des neuen Dienstes muss dieser, sofern nicht automatisch geschehen, auch gleich gestartet werden. Dies knnten Sie mit Hilfe der Systemsteuerung durchfhren, aber da wir gerade im MS-DOS-Fenster sind, erledigen wir es durch einen erneuten Aufruf des Instanzen-Managers mit folgenden Parametern:
oradim80 -startup -sid db01 -starttype srvc,inst -usrpwd oracle -pfile E:\ORANT\database\db01\initdb01.ora

Wie gesagt, normalerweise ist das nicht notwendig, da der Dienst wegen des von uns vergebenen Startmodus nach der Anlage auch sofort gestartet wird. Ansonsten haben die diesmal verwendeten Parameter folgende Bedeutung: Mit Hilfe des Parameters starttype legen Sie fest, ob das Programm den Service (srvc), die Datenbankinstanz (inst) oder beides starten soll. Beim Betrachten dieses Programmaufrufs schleicht sich der Verdacht ein, dass man Oracle-Datenbank auf einem NT-Rechner auch ohne Diensteintrge administrieren kann. Dem ist in der Tat so und wir werden uns das im weiteren Verlauf auch noch anschauen. Die Dienste sind unter NT nur ein Hilfsmittel, den Job des Rauf- und Runterfahrens von Instanz und Datenbank zu vereinfachen. Mehr Informationen ber ORADIM80 finden Sie im Buch Oracle8 Getting Started for Windows NT im Kapitel 4 Database Tools und die 8i-Anwender knnen die Informationen im Buch Oracle8i Administrator's Guide for Windows NT nachschlagen. Anlegen der neuen Datenbank Die Anlage der neuen Datenbank erfolgt mit Hilfe spezieller Befehle, die ber die zugehrige Instanz abgesetzt werden. Zum Absetzen solcher (SQL-) Befehle erhalten Sie im Rahmen der Installation verschiedene Werkzeuge, sogenannte SQL-Editoren wie beispielsweise SQL*Plus oder das SQL-Worksheet. Da wir zur Zeit aber lediglich ein Halbfertigprodukt besitzen, bentigen wir einen besonders systemnahen SQL-Editor, mit dem wir uns an die noch ohne Datenbank laufende Instanz anmelden knnen. Einen solches Werkzeug finden Sie unter Windows NT fr Oracle 8 im Programm SVRMGR30.EXE. Dieser sogenannte Server Manager ist in der Lage, sich auch ohne Datenbank mit der Datenbankinstanz zu verbinden. Fr andere Betriebssysteme existieren hnliche Programme, beispielsweise SQLDBA unter AIX. Auch dieses Programm hat in der 8i-Version einen anderen Namen und heit diesmal nur SVRMGRL.EXE. Diese Programme haben noch eine weitere gemeinsame Eigenschaft, denn Sie ermglichen die Verbindung mit dem DBMS ohne spezielle Konfiguration des Oracle-Netzwerkes Net8, weshalb das jeweilige Programm auf dem Datenbankser-

70

Oracle erste Schritte

ver gestartet werden muss. Die Vorgabe, mit welcher Datenbankinstanz sich der Server-Manager beim Start verbinden soll, erfolgt mit Hilfe einer Umgebungsvariablen bzw. bei NT mit Hilfe eines Eintrags in der Registrierungsdatenbank. Im Verzeichnis \HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE finden Sie den Eintrag ORACLE_SID. Der zugehrige Wert beschreibt den System Identifer, an dem sich der Server-Manager anzumelden versucht. Wenn Sie den Wert temporr ndern mchten, mssen Sie jedoch nicht jedes Mal den Registrierungseintrag ndern, sondern Sie knnen ihn mit Hilfe des SET-Kommandos berschreiben.
SET ORACLE_SID=db01

Im brigen entspricht auch dies der prinzipiellen Vorgehensweise fr andere Betriebssysteme. Alles, was Sie unter NT in der Registrierung finden oder per SETKommando setzen knnen, mssen Sie unter UNIX entsprechend exportieren (z.B. EXPORT ORACLE_SID=db01). Starten Sie nun den Server-Manager auf Ihrem Datenbankserver, indem Sie zunchst ein MS-DOS-Fenster ffnen, danach die Umgebungsvariable ORACLE_SID entsprechend setzen und dann das Programm SVRMGR30.EXE bzw. SRVMRGL.EXE aufrufen (vgl. Abb. 1.38).

Abbildung 1.38: Starten des Server-Managers zum Anlegen der DB01-Datenbank

Auch nach dem Start des Server-Managers erinnert das Programm immer noch an ein MS-DOS-Fenster; lediglich der Eingabeprompt hat sich von C:\> auf SVRMGR> gendert. Da wir spter noch wesentlich komfortablere SQL-Eingabewerkzeuge kennen lernen werden, mchte mit der Bedienung des Server-Managers nicht viel Zeit verbringen. Am Eingabeprompt knnen Sie die bentigen Befehle eintippen. Sofern Sie viel Platz brauchen und der konkrete Befehl dies zulsst, knnen Sie die Zeile mit Hilfe der Eingabetaste wechseln. In dem Fall mssen Sie die gesamte Befehlskette mit einem Semikolon (;) abschlieen. Es gibt aber auch Befehle, die sind sofort scharf, d.h. nach dem Drcken der Eingabetaste erhalten Sie hier keine zweite Zeile, sondern der Server-Manager beginnt sofort mit der Verarbeitung Ihrer Eingabe. Am besten verwenden Sie am Eingabeprompt des Server-Managers lediglich folgende zwei Befehle:

Erstellen einer Datenbank

71

: :

Exit Beendet den Server-Manager, d.h. Sie kehren zum MS-DOS-Eingabefenster zurck. @ Schreiben Sie hinter dem Klammeraffen den Pfad und Namen eines Skripts, das die einzelnen auszufhrenden Befehle enthlt. Dieses Skript knnen Sie mit jedem beliebigen Texteditor erstellen, so dass Sie die bentigten Befehle wenigstens entsprechend komfortabel erfassen bzw. bearbeiten knnen. Noch besser ist vielleicht sogar, Sie verwenden den Server-Manager berhaupt nicht interaktiv, sondern starten ihn immer zusammen mit einem Befehlsskript, dessen Namen Sie als Kommandozeilenparameter bergeben:
SVRMGR30 @%oracle_home%\database\db01\credb01_1.sql

Zum Anlegen unserer neuen Datenbank knnen Sie das folgende Skript verwenden, das Sie auch auf der Begleit-CD im \DB01-Verzeichnis unter dem Namen CREDB01_1.SQL finden:
# Erstellung der Datenbank DB01 spool c:\temp\credb01_1.log set echo on connect INTERNAL/oracle startup nomount pfile=E:\ORANT\database\db01\initdb01.ora create database datenb01 CONTROLFILE REUSE LOGFILE 'E:\ORANT\database\db01\logdb011.ora' SIZE 200K, 'E:\ORANT\database\db01\logdb012.ora' SIZE 200K MAXLOGFILES 32 MAXLOGMEMBERS 2 MAXLOGHISTORY 1 DATAFILE 'E:\ORANT\database\db01\Sys1db01.ora' SIZE 50M MAXDATAFILES 254 MAXINSTANCES 1 CHARACTER SET WE8ISO8859P1 NATIONAL CHARACTER SET WE8ISO8859P1; spool off
Listing 1.8: Beispiel eines Skripts zum Anlegen einer Datenbank

Zunchst wird in dem Skript mit Hilfe des connect-Kommandos eine Verbindung zur Datenbankinstanz hergestellt. Danach wird die Instanz durch Verwendung des startup-Befehls gestartet bzw. initialisiert. Der Parameter nomount sorgt dafr, dass die Datenbank hierbei nicht geffnet wird und der pfile-Parameter verweist wieder auf unsere INITDB01.ORA-Datei.

72

Oracle erste Schritte

Wesentlichster Bestandteile der eben abgebildeten Befehlsfolge ist sicherlich die Anweisung create database, mit dem unsere neue Datenbank datenb01 angelegt wird. Entsprechend der bersicht in Abbildung 1.37 legen wir hierbei das erste Datenfile (SYS1DB01.ORA) und die beiden Logdateien (LOGDB011.ORA bzw. LOGDB012.ORA) an. Ferner wird automatisch der Tablespace SYSTEM und das gleichnamige Rollback-Segment angelegt. Abspielen verschiedener Standardskripte Nun haben wir endlich eine neue Datenbank, allerdings eine im Miniaturformat. Damit meine ich nicht die anfngliche Gre des Datenfiles, sondern in der Datenbank fehlen eine Menge von Systemobjekten, die teilweise auch fr die Arbeit mit dem ein oder anderen Werkzeug notwendig sind. Auerdem sollte eine Datenbank mindestens einen weiteren Tablespace fr die Anlage und Speicherung von Benutzerdaten und weitere Rollback-Segmente (ebenfalls mit eigenem Tablespace) haben. Zumindest fr die erste der beiden Aufgaben, dem Anlegen der bentigten Systemobjekte, liefert Oracle zwei Standardskripte, die Sie im \RDBMSxx-Unterverzeichnis finden. Es handelt sich hierbei um die Dateien CATALOG.SQL und CATPROC.SQL. In der ersten Datei werden mit Hilfe entsprechender SQL-Kommandos eine Reihe von Views und anderen Objekten angelegt. Die zweite Datei ist scheinbar krzer, allerdings werden von hier weitere unzhlige Skripts gestartet. Natrlich knnten Sie nun mit Hilfe des Server-Managers diese beiden Skripte abspielen und anschlieend auch mit Hilfe entsprechender SQL-Befehle weitere Datenfiles, Tablespaces und Rollback-Segmente anlegen. Wir halten aber einen Moment inne, denn es gibt eine einfache Mglichkeit, ein fertiges Kochrezept fr die notwendige Nachbearbeitung zu erhalten.

1.5.3

Der Oracle Database Assistant

Wie Sie ja schon gemerkt haben, tauchen mit der Version 8 auch bei Oracle mehr und mehr Assistenten fr die Erledigung bestimmter Aufgaben auf. Das gilt im brigen auch bei der Erstellung einer neuen Datenbank, denn auch hierfr bietet Ihnen das System seine Untersttzung in Form eines Assistenten an. blicherweise finden Sie fr diesen Assistenten ein entsprechendes Symbol in Ihrer Programmgruppe Oracle for Windows NT. Nun muss ich allerdings einschrnken, dass in dem Fall das Wrtchen blicherweise voraussetzt, dass Sie den Assistenten bei der Installation von Oracle ausgewhlt haben; falls nicht, dann empfiehlt es sich, das in jedem Fall nachzuholen. Unter 8i gibt es den Database Configuration Assistant natrlich auch, wobei die beiden Programme mal wieder nahezu identisch sind bzw. sich lediglich in Bezug auf die Oberflche unterscheiden.

Erstellen einer Datenbank

73

Mit Hilfe des Oracle Database Assistant knnen Sie eigene Oracle-Datenbanken erstellen. Hierbei haben Sie die Wahl, die Datenbank abstrakt im Hintergrund erstellen zu lassen, oder Sie erstellen mit Hilfe des Assistenten lediglich die zur Generierung bentigten Skripte. Wie Sie dem ersten Programmfenster (vbl. Abb. 1.39 bzw. Abb.1.40) brigens entnehmen knnen, eignet sich der Assistent auch zum Lschen vorhandener Datenbanken, wobei er dabei auch in der Windows-Systemumgebung aufrumt und beispielsweise die zugehrigen Dienste lscht.

Abbildung 1.39: Der Oracle Database Assistant

Abbildung 1.40: Datenbank-Konfigurationsassistent unter 8i

74

Oracle erste Schritte

Da wir noch immer dabei sind, unsere neue Datenbank zu vervollstndigen, geht es mit der ersten Option Create a database bzw. Erstellen einer Datenbank weiter zur zweiten Seite des Assistenten. Dort haben Sie die Wahl zwischen einer Standardgenerierung und einer benutzerdefinierten Variante (Custom). Beachten Sie, dass nur diese zweite Variante die Mglichkeit bietet, die bentigten Befehle in einem Skript zu speichern, weshalb wir nach Auswahl der Option Custom bzw. Benutzerdefiniert auf die dritte Assistentenseite wechseln. Mit Hilfe dieser dritten Seite knnen Sie die Installation verschiedener Zusatzpakete veranlassen, allerdings wird die Auswahl nur angeboten, wenn Sie die zugehrigen Features im Rahmen der Softwareinstallation ausgewhlt haben. Beim 8i-Assistenten whlen wir hier die Option Mehrzweck und danach geht es in jedem Fall gleich weiter zur vierten Seite (vgl. Abb. 1.41 bzw. Abb. 1.42), in der Sie endlich mal wieder etwas eingeben mssen.

Abbildung 1.41: Festlegen verschiedener Datenbankparameter

Ich hatte noch nicht verraten, dass auch die bentigten Konfigurationsdatei (INITSID.ORA) durch den Assistenten erstellt wird. Mit Hilfe der drei Optionen Small, Medium bzw. Large legen Sie die Gre des Shared Pools (vgl. Kap. 1.1.2) mit Hilfe des shared_pool_size-Eintrags und weiterer Parameter fest. Oracle empfiehlt verschiedene Einstellungen in Abhngigkeit der gleichzeitig arbeitenden Benutzer. Fr bis zu 10 Anwender wird klein (Small), zwischen 11 und 100 mittel (Medium) und ab 101 Benutzer die Einstellung gro (Large) empfohlen. In unserer Konfigurationsdatei hatten wir hierfr berhaupt keine Parameter explizit vorgegeben, da ihre Standardwerte der Einstellung klein entsprechen. Entsprechend der Empfehlung, die Gre von den parallel arbeitenden Benutzern abhngig zu machen, ist die vierte Seite des 8i-Assistenten (vgl. Abb. 1.42) gendert worden und fragt ganz einfach diese Benutzerzahl ab.

Erstellen einer Datenbank

75

Abbildung 1.42: Festlegen der Gre mit dem 8i-Assistenten

Beachten Sie allerdings, dass die hier getroffene Einstellung noch nicht direkt zu Eintrgen in der Konfigurationsdatei fhrt. Spter auf einer der folgenden Seiten des Assistenten haben Sie noch die Mglichkeit, die verschiedenen SGA-Parameter explizit vorzugeben, wobei die dort voreingestellten Werte allerdings von der hier gemachten Grenvorgabe abhngen. Wichtig ist auch die Kontrolle des eingestellten Zeichensatzes, da sich dieser nach Erstellung der Datenbank nicht mehr ndern lsst. Der gewhlte Zeichensatz regelt unter anderem die Darstellung von Tabellennamen und wird ebenfalls beim Speichern von SQL-Programmen herangezogen. Von hier ab laufen die Bilder des 8erund 8i-Assistenten allerdings zunchst einmal auseinander. Die Auswahl des Zeichensatzes erfolgt erst ein paar Seiten spter, wobei der 8i-Assistent bis dahin noch weitere zustzliche Parameter abfragt. Mit Hilfe der Schaltflche Change Character Set bzw. spter Zeichensatz ndern knnen Sie die Voreinstellung berprfen bzw. ndern. Falls ntig, sollten Sie den Wert auf WE8ISO8859P1 ndern. Das steht fr ISO 8859-1 West European und hrt sich, so finde ich, ziemlich gut an. brigens, wenn Sie sich einmal einer unbekannten Datenbank nhern, dann knnen Sie diese Einstellung berprfen, indem Sie folgende Abfrage eingeben:
select * from v$nls_parameters

Die nchste Seite des Assistenten bzw. eine der folgenden bei der 8i-Version (vgl. Abb. 1.43 bzw. Abb. 1.44) ermglicht Ihnen die Eingabe des Datenbanknamens, des System Identifers (SID) und weiterer Parameter, die Sie aufgrund des vorherigen Kapitels alle schon kennen.

76

Oracle erste Schritte

Abbildung 1.43: Datenbanknamen, SID und weitere Parameter vorgeben

Abbildung 1.44: Datenbanknamen, SID und Zeichensatz beim 8i-Assistenten vorgeben

Eigentlich wollen wir die Datenbank DB01 fertigstellen, allerdings erhalten Sie bei entsprechender Eingabe ein kleines Problem in Form einer Fehlermeldung, nachdem Sie versuchen, auf die nchste Seite des Assistenten zu wechseln. Der Oracle Database Assistent merkt nmlich, das die Datenbankinstanz DB01 schon von uns erstellt wurde und fordert Sie daher auf, eine andere SID einzugeben. Da wir aber eigentlich nur die zur Nachbearbeitung erforderlichen Skripte wollen, mssen wir hier ein wenig schummeln und geben im Feld SID db02 oder irgendetwas anderes ein, um anschlieend auf die nchste Seite wechseln zu knnen.

Erstellen einer Datenbank

77

Auf dieser mittlerweile sechsten (bzw. achten) Seite haben Sie die Mglichkeit, die Namen der Kontrolldateien sowie die Anzahl der zulssigen Datenfiles vorzugeben. Das alles hatten wir in unserer manuell erstellten Konfigurationsdatei INITDB01. ORA bzw. beim Absetzen des create database-Befehls schon festgelegt, so dass Sie diesmal ohne irgendwelche Eingabe mit der siebten (neunten) Seite fortfahren knnen.

Abbildung 1.45: Anlegen zustzlicher Files, Tablespaces und Rollback-Segmente

Abbildung 1.46: Anlegen zustzlicher Tablespaces beim 8i-Assistenten

78

Oracle erste Schritte

Auf der siebten bzw. neunten Seite (vgl. Abb. 1.45 oder Abb. 1.46) des Assistenten wird es endlich so richtig interessant. Mit Hilfe der fnf bzw. sechs verschiedenen Registerkrtchen knnen Sie sowohl den Systembereich - das ist fr uns allerdings nicht mehr so wichtig - genauer definieren, als auch weitere Dateien, Tablespaces und Rollback-Segmente anlegen. Die hier gezeigten Mglichkeiten entsprechen im brigen auch den von Oracle gemachten Empfehlungen, zumindest noch weitere Dateien bzw. Tablespaces fr Benutzerdaten, Rollback-Segmente, Indizes und einen speziellen Bereich fr temporre Aktivitten anzulegen. Wie Sie beim Vergleich der beiden Abbildungen 1.45 und 1.46 feststellen knnen, besitzt die 8i-Datenbank standardmig einen zustzlichen Tablespace mit dem Namen TOOLS. Tragen Sie fr alle Registerkrtchen die gewnschten Dateinamen im Feld File und die Namen der Tablespaces im Feld Name ein. Achten Sie hierbei darauf, dass alle Verzeichnisse und Namen zu Ihrer neuen DB01-Instanz gehren, damit das spter erstellte Skript ohne nderung verwendbar ist. Rechts neben dem Namensfeld knnen Sie die anfngliche Gre des Tablespace angeben. Im unteren Bereich des Bildes haben Sie die Mglichkeit, eine allgemeine Speicherbelegungsregel (vgl. Kap. 1.1.3) fr den Tablespace vorzugeben. Wie Sie spter noch sehen werden, knnen Sie diese Regel bei Bedarf fr jede einzelne Tabelle noch ndern. Besonders interessant ist die Einstellung des Schalters Auto Extend. Ist er so wie in unserem Beispiel eingeschaltet, dann wird der Tablespace bzw. die zugehrige Datei bei Bedarf automatisch vergrert. Wenn Sie diese Funktion ausschalten, dann mssen Sie die Datei im Bedarfsfall selbst vergrern oder dem Tablespace ein weiteres Datenfile zuweisen. Genaueres zu diesem Thema erfahren Sie allerdings erst spter, wenn wir im weiteren Verlauf noch einmal auf die Administration von Dateien und Tablespaces zurckkommen werden. Hier und jetzt knnen Sie die vom Assistenten vorgeschlagenen Werte zunchst einmal so bernehmen und in der Parametrierung der bentigten Erstellungsskripte mit der nchsten Seite fortfahren. Die achte (bzw. zehnte) Seite des Assistenten bringt fr uns wieder mal nichts Neues. Hier mssen Sie die Namen der bentigten Log-Dateien festlegen, die wir allerdings schon bei der create database-Anweisung zugeordnet haben und die im Rahmen der Ausfhrung dieses Befehls auch bereits angelegt wurden. Also knnen Sie gleich mit der nchsten Seite des Assistenten fortfahren. Mit Hilfe der neunten (elften) Assistentenseite (vgl. Abb. 1.47 bzw. Abb. 1.48) knnen Sie verschiedene Einstellungen vornehmen, die zu entsprechenden Parametern in der Konfigurationsdatei fhren. Mit Hilfe des Kontrollkstchens Archive Log veranlassen Sie beispielsweise die Archivierung der redo log-Eintrge (vgl. Kap. 1.5.1). Das Einschalten dieser Option fhrt zum Setzen der Parameter log_archive_ dest, log_archive_format, log_archive_buffers und log_archive_buffer_size, mit denen vor allem das Format und der Zielort der Archivdateien festgelegt werden. Soll die Archivierung automatisch mit dem Initialisieren der Datenbankinstanz gestartet werden, dann mssen Sie in der Konfigurationsdatei zustzlich noch den Parameter log_archive_start = true vorgeben.

Erstellen einer Datenbank

79

Abbildung 1.47: Festlegen weiterer Parameter der Konfigurationsdatei

Abbildung 1.48: Einstellen der Logging-Parameter im 8i-Assistenten

Die anderen beiden Eingabefelder des Dialogs legen die Werte fr die Parameter log_checkpoint_interval bzw. log_checkpoint_timeout fest. Der erste der beiden Werte regelt, wie hufig zustzliche Checkpoints generiert werden, wobei der zweite Wert den notwendigen Abstand zwischen zwei Checkpoints bestimmt. bernehmen Sie die beiden vorgeschlagenen Werte ohne nderung in Ihre neue Konfigurationsdatei und wechseln Sie zur nchsten Seite des Datenbankassistenten.

80

Oracle erste Schritte

Abbildung 1.49: Festlegen der SGA-Dimensionierung

Mittlerweile sind wir auf der zehnten (zwlften) Seite (vgl. Abb. 1.49 und Abb. 1.50) des Assistenten angelangt. Mit Hilfe der hier vernderbaren Werte knnen Sie die SGA Ihrer Instanz konfigurieren. Die konkret vorgeschlagenen Werte hngen von der zuvor auf Seite vier vorgegebenen Datenbankgre ab.

Abbildung 1.50: Festlegen der SGA-Konfiguration beim 8i-Assistenten

Erstellen einer Datenbank

81

Mit Hilfe des ersten Feldes (Shared Pool Size bzw. gemeinsamer Pool) bestimmen Sie den Wert fr den Parameter shared_pool_size und damit die Gre des Shared Pools (vgl. Kap. 1.1.2) in Byte. Mehr ist nicht unbedingt immer besser. Sicherlich gilt im Mehrbenutzerbetrieb, dass der Shared Pool mglichst gro gewhlt werden muss, allerdings sollten Sie darauf achten, dass der geforderte Speicher auf dem Rechner auch permanent verfgbar ist. Der Schuss geht nmlich wie man so schn sagt nach hinten los, wenn aufgrund der eingestellten Gre sich bestimmte Teile des Pools hufig im Auslagerungsspeicher befinden bzw. das Betriebssystem dauernd damit beschftigt ist, SGA-Teile im Hauptspeicher einbzw. auszulagern. Aus diesem Grund habe ich diesen Wert auf 35 MB gendert. Das soeben Gesagte gilt natrlich nicht nur fr den Shared Pool, sondern fr die gesamte SGA. Auch die anderen Puffer sollten so dimensioniert werden, dass die gesamte SGA permanent im Hauptspeicher Platz findet. Das nchste Feld Block Buffers bzw. Blockpuffer legt ber den Parameter db_block_buffers die Anzahl der Blcke im Database Buffer Cache, das war derjenige Speicher in dem die gerade bentigten Datenblcke zwischengespeichert werden, fest. Zusammen mit dem Parameter db_block_size, der die Gre eines solchen Blockes festlegt und der mit Hilfe des letzten Eingabefeldes verndert werden kann, ergibt sich somit die gesamte Gre des Buffer Caches. In unserem Beispiel knnen wir mit der Vorgeschlagenen Anzahl von 200 Datenblcken gut leben. Die Gre eines solchen Blockes belasse ich auf 2048 Byte, was im brigen auch dem Standardwert dieses Parameters entspricht. Das dritte Eingabefeld dimensioniert die Gre des Log-Buffers und fhrt in der Konfigurationsdatei zum gleichnamigen Parameter (log_buffer). Je grer der zugehrige Wert, um so seltener muss der LGWR-Prozess den Puffer in die aktuelle redo log-Datei kopieren. In unserem Beispiel belassen wir den Wert unverndert auf 8192 Byte. Mit Hilfe des Datenfeldes Processes knnen Sie die maximale Anzahl von Benutzerprozessen bestimmen, die sich gleichzeitig an der Oracle-Datenbank anmelden knnen. Der Eintrag fhrt in der Konfiguration zum Parameter processes, dessen Standardwert 30 betrgt. Der Wert wrde fr unsere Spiel- und Trainingsdatenbank sicherlich ausreichen, jedoch ist gegen den vorgeschlagenen Wert von 50 auch nichts einzuwenden. Nachdem Sie nun die wesentlichen SGA-Einstellungen der Oracle-Instanz festgelegt haben, knnen Sie mit dem Assistenten auf die nchste und vorletzte Seite wechseln. Dort finden Sie zwei Eingabefelder, in denen Sie Verzeichnisse fr die Erstellung von Tracedateien festlegen knnen. In der Konfigurationsdatei finden Sie die hier vorgegebenen Einstellungen in den Parametern user_dump_dest bzw. background_dump_dest wieder.

82

Oracle erste Schritte

Abbildung 1.51: Endlich am Ziel, im nchsten Schritt werden die Skripte erstellt

Mit der nchsten Seite des Assistenten (vgl. Abb. 1.51 bzw. Abb. 1.52) sind wir endlich am Ziel bzw. stehen kurz davor. Mit Hilfe der entsprechend Option erhalten Sie nach Auswahl der Finish- bzw. Fertig-Schaltflche die Mglichkeit, ein Verzeichnis und den Namen einer Batchdatei festzulegen. Die Batchdatei (z.B. SQL.BAT) enthlt alle Befehle, die zum Anlegen der Instanz und Datenbank notwendig sind. Einige der dort enthaltenen Schritte hatten wir im Verlauf des vorhergehenden Kapitels schon ausgefhrt. Zustzlich erhalten Sie zwei SQL-Skripte, deren Namen der vergebenen Datenbank-SID entsprechen (z.B. DB02.SQL und DB021.SQL).

Abbildung 1.52: Beim 8i-Assistenten sind Sie ebenfalls am Ziel angelangt

Erstellen einer Datenbank

83

Das erste Skript enthlt den create database-Befehl, den wir ebenfalls schon ausgefhrt hatten. Das zweite und die eventuell folgenden Skripte vereinen alle notwendigen Schritte, um die bisherige Rudimentrdatenbank fertigzustellen. Auf Ihrer Begleit-CD finden Sie die vom Assistenten erstellte Konfigurationsdatei im \DB01Unterverzeichnis unter dem Namen INITDB01A.ORA. Sie knnen die DB01Instanz zuknftig auch mit dieser generierten Konfigurationsdatei hochfahren , d.h. in dem Fall mssen Sie Ihre aktuelle Konfigurationsdatei ersetzen. Das zweite SQL-Skript finden Sie im gleichen Verzeichnis, heit CREDB01_2.SQL und hat folgenden Inhalt:
spool c:\temp\credb01_2.log set echo on connect INTERNAL/oracle

1. ALTER DATABASE DATAFILE 'E:\ORANT\database\db01\Sys1db01.ora' AUTOEXTEND ON; 2. CREATE ROLLBACK SEGMENT SYSROL TABLESPACE "SYSTEM" STORAGE (INITIAL 100K NEXT 100K); ALTER ROLLBACK SEGMENT "SYSROL" ONLINE; @E:\ORANT\Rdbms80\admin\catalog.sql; @E:\ORANT\Rdbms80\admin\catproc.sql 3. REM **************TABLESPACE FOR ROLLBACK***************** CREATE TABLESPACE RBS DATAFILE 'E:\ORANT\database\db01\Rbs1db01.ora' SIZE 10M DEFAULT STORAGE ( INITIAL 1024K NEXT 1024K MINEXTENTS 2 MAXEXTENTS 121 PCTINCREASE 0); ALTER DATABASE DATAFILE 'E:\ORANT\database\db01\Rbs1db01.ora' AUTOEXTEND ON; 4. REM ***********Alter system tablespace ******************** ALTER TABLESPACE SYSTEM DEFAULT STORAGE ( INITIAL 100K NEXT 100K MINEXTENTS 1 MAXEXTENTS 300 PCTINCREASE 1);

5. REM **************TABLESPACE FOR USER********************* CREATE TABLESPACE USR DATAFILE 'E:\ORANT\database\db01\Usr1db01.ora' SIZE 3M DEFAULT STORAGE ( INITIAL 50K NEXT 50K MINEXTENTS 1 MAXEXTENTS 121 PCTINCREASE 1); ALTER DATABASE DATAFILE 'E:\ORANT\database\db01\Usr1db01.ora' AUTOEXTEND ON;
REM **************TABLESPACE FOR TEMPORARY***************** CREATE TABLESPACE TEMPORARY DATAFILE 'E:\ORANT\database\db01\Tmp1db01.ora' SIZE 10M DEFAULT STORAGE ( INITIAL 100K NEXT 100K MINEXTENTS 1 MAXEXTENTS 121 PCTINCREASE 0) TEMPORARY; ALTER DATABASE DATAFILE 'E:\ORANT\database\db01\Tmp1db01.ora' AUTOEXTEND ON; REM **************TABLESPACE FOR INDEX*********************

84

Oracle erste Schritte

CREATE TABLESPACE INDX DATAFILE 'E:\ORANT\database\db01\Indx1db01.ora' SIZE 10M DEFAULT STORAGE ( INITIAL 50K NEXT 50K MINEXTENTS 1 MAXEXTENTS 121 PCTINCREASE 1); ALTER DATABASE DATAFILE 'E:\ORANT\database\db01\Indx1db01.ora' AUTOEXTEND ON; 6. REM **** Creating two rollback segments **************** CREATE ROLLBACK SEGMENT RB0 TABLESPACE "RBS" STORAGE ( INITIAL 50K NEXT 50K MINEXTENTS 2 MAXEXTENTS 121 ); CREATE ROLLBACK SEGMENT RB1 TABLESPACE "RBS" STORAGE ( INITIAL 50K NEXT 50K MINEXTENTS 2 MAXEXTENTS 121 ); ALTER ROLLBACK SEGMENT "RB0" ONLINE; ALTER ROLLBACK SEGMENT "RB1" ONLINE; 7. alter user sys temporary tablespace TEMPORARY; alter user system default tablespace USR; alter rollback segment "SYSROL" offline; spool off
Listing 1.9: Typisches Nachlauf Skript zum Fertigstellen einer Datenbank

Bei der Erstellung einer Datenbank fr die 8i-Version enthlt das Skript natrlich auch die Erstellung des zustzlichen Tablespaces TOOLS. Auf der CD finden Sie daher auch noch die Datei CREDB01_2I.SQL als Muster fr ein solches Skript bei der 8i-Version. Das Skript knnen Sie wieder mit Hilfe des Server-Managers starten, in dem Sie in einem MS-DOS-Fenster Folgendes eingeben:
Set oracle_sid=db01 svrmgr30 @e:\orant\database\db01\credb01_2.sql

Den Pfad und Namen des Skriptes mssen Sie natrlich Ihren individuellen Gegebenheiten anpassen. Die Ausfhrung des Skripts kann je nach Rechner durchaus 30 bis 60 Minuten dauern; das liegt vor allem an der Datei CATPROC.SQL, aus der endlos viele weitere SQL-Befehlsdateien gestartet werden. Whrend der Ausfhrung knnen Sie die verschiedenen Aktionen am Bildschirm mitverfolgen, zumindest wenn Sie schnell genug lesen knnen; gut, dass alle Aktivitten in dem mit der spool-Anweisung vorgegebenen Datei protokolliert werden. In den folgenden Abschnitten finden Sie eine kurze Beschreibung der verschiedenen Passagen des SQL-Skripts. Die im Listing abgedruckten Nummern sind in der Originaldatei natrlich nicht enthalten. Auerdem finden Sie weitergehende Informationen zu den einzelnen Befehlen entweder am Ende des Kapitels 5. Datenbankprogrammierung oder in der SQL-Reference der Oracle-Dokumentation. Nun zu den einzelnen Passagen des abgedruckten Skripts: 1. Fr das Datenfile des Systembereichs wird die autoextend-Eigenschaft eingeschaltet, damit es anschlieend beliebig wachsen kann.

Erstellen einer Datenbank

85

2. Im SYSTEM-Tablespace wird ein weiteres Rollback-Segment angelegt. Dieses Rollback-Segment ist von der Gre her so dimensioniert, dass alle nachfolgenden Statements ausgefhrt werden knnen. Anschlieend wird das RollbackSegment aktiviert und danach werden nacheinander die beiden Skripte CATALOG.SQL und CATPROC.SQL aufgerufen. 3. In dem Schritt wird der Tablespace RBS im Datenfile RBS1DB01.ORA angelegt. Hierbei werden die im Assistenten spezifizierten Regeln zur Speicherbelegung (storage-Klausel) verwendet. Anschlieend wird der Autoextend-Modus fr die Datei eingeschaltet. 4. Das Verfahren zur Speicherbelegung wird fr den SYSTEM-Tablespace angepasst. 5. hnlich wie im Punkt 3 werden die Tablespaces USR, TEMPORY und INDX mitsamt den Dateien USRLDB01.ORA, TMP1DB01.ORA und INDX1DB01.ORA entsprechend den im Assistenten gemachten Vorgaben angelegt. 6. Es werden zwei neue Rollback-Segmente RB0 und RB1 im RBS-Tablespace angelegt und anschlieend aktiviert. Beachten Sie nochmals, dass Sie die Verwendung der beiden Rollback-Segmente in der Konfigurationsdatei der Instanz noch einschalten mssen:
rollback_segments = (RB0, RB1)

7. Fr die angelegten Benutzer sys und system wird die jeweilige Standard-Tablespace-Zuordnungen gendert. Anschlieend wird das am Anfang angelegte Rollback-Segment SYSROL deaktiviert. Endlich fertig; Sie sind im Besitz einer eigenen voll funktionsfhigen Datenbank. Neben der Benutzer-Id INTERNAL mit dem whrend der Installation vorgegebenen Passwort legt Oracle whrend der Datenbankanlage weitere Benutzer-Ids an. Wir werden spter im Workshop bei der Behandlung von Benutzer- und Rollenprofilen sehen, welche IDs alle schon in der Datenbank vorhanden sind. Vorab schon mal eine kleine bersicht der vorhandenen Benutzer mit Administratorrechten:
Benutzer-ID INTERNAL SYS SYSTEM CHANGE_ON_INSTALL MANAGER Passwort

Tabelle 1.3: bersicht der standardmig vorhandenen DBA-Accounts

Die insgesamt generierten oder aufgerufenen Skripte hngen konkret von der verwendeten Datenbankversion und von den installierten Zusatzoptionen ab. Von daher ist es natrlich nicht besonders empfehlenswert, bei der Anlage einer Datenbank die auf der CD befindlichen Muster zu verwenden, sondern sich mit Hilfe der Assistenten einen individuellen Ablauf zu generieren und unter NT vielleicht auch automatisch abzuspielen.

86

Oracle erste Schritte

1.5.4

Automatische Generierung unter NT

Wie Sie im bisherigen Verlauf des Buches vielleicht schon gemerkt haben, fhren in Oracle meistens nicht nur mehrere, sondern immer gleich viele Wege zum Ziel. Dabei geht es gar nicht unbedingt immer nur um die Abwgung zwischen einem manuellen oder abstraktem vollautomatischen Verfahren, sondern viele vorhandene Werkzeuge haben einen sich berschneidenden Aktionsbereich, so dass es manchmal reine Geschmacksache ist, ob man eine Aufgabe mit diesem oder jenem Hilfsmittel bewerkstelligt. Ein Beispiel fr diese Aufgabenberlappung stellt auch die Mglichkeit dar, eine neue Datenbankinstanz nebst Datenbank mit Hilfe des schon bekannten Programms ORADIM80.EXE zu generieren, was allerdings in der hier beschriebenen Form unter 8i nicht mehr bzw. in anderer Form mit Hilfe des neuen Assistenten funktioniert. Dieses Programm, das es in der entsprechenden Vorgngerversion auch schon unter Version 7 gab, habe ich vor allem frher immer ganz gerne genutzt, um einfach und schnell einen neue Datenbank zu erzeugen. Starten Sie hierzu einfach das Programm ORADIM80.EXE ohne weitere Parameter. Als Ergebnis erhalten Sie ein kleines Programmfenster, in dem alle auf dem Rechner vorhandenen Datenbankinstanzen angezeigt werden. Whlen Sie hier die Schaltflche New, um die Erstellung einer neuen Datenbankinstanz einzuleiten.

Abbildung 1.53: Anlegen einer neuen Datenbankinstanz

Auf der ersten Seite (vgl. Abb. 1.53) zur neuen Datenbankinstanz mssen Sie als Erstes den System-Identifer (SID) der neuen Datenbank (z.B. db01) angeben. Anschlieend trgt das Programm den Namen der zugehrigen Initialisierungdatei (INTIDB01.ORA) automatisch rechts unten in das zugehrige Eingabefeld ein. Legen Sie als Nchstes das Passwort fr den Benutzer INTERNAL fest, das Sie im folgenden Feld noch einmal besttigen mssen. Danach wechseln Sie mit Hilfe der Schaltflche Advanced auf die zweite Seite, um weitere Einstellungen fr die Generierung vorzunehmen.

Administrierung der Datenbanken

87

Abbildung 1.54: Anlegen weiterer Generierungsparameter fr die neue Datenbank

Auf der zweiten Seite (vgl. Abb. 1.54) mssen Sie den Datenbanknamen vorgeben, der dem Namen aus der Initialisierungsdatei entsprechen muss. Anschlieend mssen Sie mindestens noch die Namen und Verzeichnisse der Logdateien und des Systembereichs festlegen. Danach knnen Sie den Dialog mit Hilfe der OK-Schaltflche beenden, wodurch Sie zum vorhergehenden Dialog zurckkehren. Beenden Sie auch diesen jetzt mittels OK, wonach das Programm mit der Erstellung der Datenbankinstanz und anschlieend mit der Generierung der Datenbank beginnt. Nach ein paar Minuten, die genaue Zeit hngt natrlich mal wieder vom Rechner ab, erscheint ein Hinweis, der es Ihnen ermglicht, ein spezielles Skript abzuspielen. Dieses Skript wurde whrend der Generierung erstellt und enthlt im Wesentlichen wieder den Aufruf der schon bekannten Dateien CATALOG.SQL und CATPROC.SQL. Das war schon alles; auch jetzt sind Sie wieder im Besitz einer neuen Datenbank. Alles was Sie zustzlich bentigen (Benutzer, Tablespaces usw.), knnen bzw. mssen Sie in weiteren Arbeitsschritten anlegen.

1.6

Administrierung der Datenbanken

Wie Sie im Kapitel 1.3 Dienste unter Windows-NT schon lesen konnten, werden die Komponenten einer Oracledatenbank unter Windows am einfachsten mit Hilfe sogenannter Dienste administriert. So einfach dieses Verfahren auch ist, es lsst auf den ersten Blick keinen direkten Vergleich zur Vorgehensweise auf andere Systeme (z.B. UNIX) zu. Dabei gibt es, zumindest was die prinzipielle Vorgehensweise angeht, eigentlich kaum Unterschiede. Auf einem Server luft die Oracle-Datenbankinstanz blicherweise als Hintergrundprozess und damit schlagen wir auch schon die Brcke zu den Windows-Diensten, denn diese Dienste sind nur ein Hilfsmittel, um solche Hintergrundprozesse zu verwalten.

88

Oracle erste Schritte

Eigentlich geht es nur darum, auf Ihrem Rechner das Programm ORACLE80.EXE (unter vielen anderen Systemen wie auch 8i einfach nur ORACLE) zu aktivieren. ffnen Sie doch einmal ein MS-DOS-Fenster (vgl. Abb. 1.55) und geben Sie am Prompt folgenden Befehl ein:

Abbildung 1.55: Starten des Oracle-Servers im Vordergrund

Hierdurch starten Sie das Programm ORACLE80.EXE, dem Sie die zugehrige SID als Kommandozeilenparameter bergeben und boom nach wenigen Sekunden erhalten Sie die abgebildete Nachricht und auf Ihrem Rechner luft die DB01Datenbankinstanz. Einen Nachteil hat das Ganze natrlich: sobald Sie das MSDOS-Fenster schlieen oder dort irgendeine Taste drcken, ist die Datenbankinstanz wieder weg, da das zugehrige ORACLE80-Programm beendet wird.

1.6.1

Instanz starten und stoppen

Um nun das ORACLE-Programm im Hintergrund zu starten, knnen Sie unter NT das schon bekannte Programm ORADIM80.EXE folgendermaen verwenden:
oradim80 -startup -sid db01 -starttype srvc oradim -startup -sid db01 -starttype srvc

Die verschiedenen Schalter und Parameter haben dabei folgende Bedeutung:

: : :

-startup Der Schalter gibt an, dass ORADIM eine Datenbankinstanz auf Ihrem Rechner (im Hintergrund) starten soll. -sid Verwenden Sie den Schalter zusammen mit dem System Identifer derjenigen Instanz, die Sie auf dem Rechner starten wollen. -starttype srvc Mit Hilfe dieses Schalters mssen Sie festlegen, wie die Datenbankinstanz gestartet werden soll. Wie Sie noch sehen werden, stehen Ihnen hierbei verschiedene Varianten zu Verfgung. Der Wert srvc fhrt zum Starten der Datenbankinstanz.

Administrierung der Datenbanken

89

Nach Eingabe des eben beschriebenen Befehls sollte die Prozess-Liste Ihres Windows Task-Managers einen weiteren Eintrag mit dem Namen ORACLE80.EXE (bzw. ORACEL80.EXE) aufweisen. In jedem Fall finden Sie Hinweise oder Fehler zum Start der Instanz in der Datei ORADIMxx.LOG, die Sie im \RDBMSxx-Unterverzeichnis Ihrer Oracle-Installation finden. brigens eignet sich ORADIM auch zum Beenden einer laufenden Instanz. In dem Fall mssen Sie das Programm folgendermaen aufrufen:
oradim80 -shutdown -sid db01 -shuttype srvc -shutmode N oradim -shutdown -sid db01 -shuttype srvc -shutmode N

: : : :

-shutdown legt fest, dass Sie eine Datenbankinstanz beenden mchten. -sid identifiziert die zu schlieende Instanz, d.h. geben Sie hier den zugehrigen System Identifer ein. -shuttype Verwenden Sie srvc, um die Datenbankinstanz zu beenden. -shutmode Mit diesem Schlssel knnen Sie die Modus fr das Herunterfahren vorgeben. Das bliche Verfahren ist das sogenannte normale Beenden der Instanz, weshalb Sie den Schalter zusammen mit dem Buchstaben N verwenden.

Beim Beenden der Datenbankinstanz wird eine eventuell geffnete Datenbank ebenfalls geschlossen. Wird die Instanz normal beendet (-shutmode N), dann wird mit dem Heruntergefahren gewartet, bis aktuell laufende Prozesse (z.B. eine Datennderung) beendet sind. Die anderen Beendigungsmethoden z.B. I (fr IMMEDIATE, engl. immediately) erzwingen ein sofortiges Beendigen der Instanz, was in der Regel zu entsprechenden Recovery-Aktivitten beim nchsten Hochfahren der Datenbank zur Folge hat. Eine vollstndige bersicht aller vorhandenen Parameter und Schalter des Programms ORADIM80.EXE erhalten Sie, wenn Sie das Programm zusammen mit dem Schalter -? oder /H aufrufen. Weitere Verwendungsformen finden Sie auch im nchsten Kapitel, denn mit dem Programm knnen Sie auch die zur Instanz gehrende Datenbank ffnen oder schlieen.

1.6.2

Datenbank ffnen und schlieen

Nach dem Hochfahren der Datenbankinstanz ist ein Arbeiten mit der zugehrigen Datenbank noch nicht mglich. Hierzu muss sie nmlich zunchst einmal noch geffnet werden. Unter NT haben Sie auch hierfr einen entsprechenden Diensteintrag, doch wie funktioniert das Verfahren ohne Dienste bzw. unter anderen Betriebssytemen?

90

Oracle erste Schritte

Beginnen wir auch diesmal zunchst mit einem leicht bertragbaren Verfahren, das ich in hnlicher Form schon in so manchen Start- bzw. Bootskripts gefunden habe. Konkret geht es darum, die Datenbank mit Hilfe des Server-Managers zu starten, indem Sie mit seiner Hilfe beispielsweise folgendes Skript abspielen:
connect internal/oracle startup pfile=e:\orant\database\db01\initdb01.ora

Nach dem Anmelden and die noch unttige Datenbankinstanz, wird die Datenbank mit Hilfe des startup-Befehls und der Vorgabe der zugehrigen Konfigurationsdatei geffnet. hnlich einfach lsst sich auch das Herunterfahren bzw. Schlieen der Datenbank bewerkstelligen:
connect internal/oracle shutdown normal

Der Zusatz normal ist brigens die standardmige Variante des shutdownBefehls, d.h. Sie knnen diesen Teil der Anweisung auch weglassen. Falls Sie wissen, dass gleich der Strom ausfllt, dann sollten Sie besser den Befehl shutdown immediate verwenden, damit alle aktiven Benutzer sofort abgehngt, alle laufenden Transaktionen zurckgerollt und die Datenbank unverzglich geschlossen wird. Diese shutdown-Variante wird im brigen auch angewendet, wenn Sie mit ORADIM80 die Instanz in der Form shutmode I herunterfahren. ffnen und Schlieen mit ORADIM Wie ich schon angedeutet hatte, besteht auch die Mglichkeit, eine Datenbank mit Hilfe des Programms ORADIMxx.EXE zu ffnen oder zu schlieen. Sie erleben also gerade mal wieder ein Beispiel fr die Vielfalt der mglichen Wege, um zum Ziel zu kommen. Das ffnen der Datenbank erfolgt bei schon laufender Instanz beispielsweise folgendermaen:
oradim80 -startup -sid db01 -starttype inst -usrpwd oracle -pfile e:\orant\database\db01\initdb01.ora

Bei Verwendung der Version 8i mssen Sie jetzt anstelle von oradim80 natrlich nur wieder oradim eingeben, da das Programm entsprechend umbenannt wurde. Neu bei dem Aufruf ist zunchst einmal der verwendete Starttyp inst, der das Programm zum ffnen der zugehrigen Datenbank veranlasst. Die Starttypen inst und svrc knnen im brigen auch gemeinsam verwendet werden (svrc, inst), um das Laden der Instanz mit dem ffnen der Datenbank zu verbinden. Dabei muss das Programm natrlich dieselben Aktivitten durchfhren, die Sie vorhin zusammen mit dem Server-Manager manuell durchgefhrt haben. Aus dem Grund bentigen Sie zwei weitere Parameter -usrpwd und -pfile, um mit deren Hilfe das Kennwort fr den Internal-Benutzer und den Pfad und Namen der Konfigurationsdatei vorzugeben.

Administrierung der Datenbanken

91

Ebenfalls mglich ist auch das Schlieen der Datenbank via ORADIM, indem Sie das Programm beispielsweise folgendermaen aufrufen:
oradim80 -shutdown -sid db01 -usrpwd oracle -shuttype inst, -shutmode N

1.6.3

Lschen einer Datenbank

Aufgrund der Oracle-Architektur sind fr das Lschen einer Datenbank keine speziellen Befehle (z.B. drop database) notwenig, da die zu lschende Datenbank ja nicht in irgendeiner Systemdatenbank des DBMS eingetragen ist, sondern zusammen mit seinem DBMS eine logische Einheit bildet. Auerdem kann man ja auch kaputtmachen, was man gleich sowieso lschen mchte. Aus dem Grund wre folgende Holzhammermethode zum Entfernen einer Oracle-Datenbank denkbar:

: : :

Beenden Sie den zugehrigen ORACLE-Hintergrundprozess, beispielsweise durch ein entsprechendes KILL-Kommando (z.B. UNIX) oder indem Sie das Programm unter Windows mit Hilfe des Task-Managers aus der Prozessliste schmeien. Entfernen Sie den Aufruf der Datenbank aus allen Startup- bzw. Boot-Skripten. Lschen Sie unter NT in der Registrierung alle eventuell vorhandenen Diensteintrge. Lschen Sie alle zugehrigen Dateien (Daten-, Log-, Kontroll- und Konfigurationsdateien).

Der Nachteil dieses Verfahrens ist natrlich, dass man hierbei genau wissen muss, was man im Einzelnen abschieen bzw. lschen darf. Schnell hat man mal daneben gegriffen und beispielsweise den falschen Prozess abgewrgt oder in der Registrierung leider den darber liegenden Dienst markiert und entfernt. Aus diesem Grund gibt es auch fr das Entfernen einer Datenbank die eine oder andere Hilfestellung. Zunchst einmal sollten Sie sich einen berblick ber die vorhandene Dateistruktur der Datenbank machen. Identifizieren Sie zunchst die verwendete Konfigurationsdatei, denn in ihr finden Sie einen Verweis auf die zur Datenbank gehrenden Kontrolldateien:
control_files = (E:\ORANT\DATABASE\db01\ctl1db01.ora,E:\ORANT\DATABASE\db01\ctl2db01.ora)

Fhren Sie mit Hilfe eines SQL-Editors, beispeilsweise dem Server-Manager, folgende Abfragen aus, um eine bersicht der zugehrigen Datendateien (vgl. Listing 1.10) und Log-Dateien (vgl. Listing 1.11) zu erhalten.
SVRMGR> select name from v$datafile; NAME ------------------------------------------E:\ORANT\DATABASE\DB01\SYS1DB01.ORA

92

Oracle erste Schritte

E:\ORANT\DATABASE\DB01\RBS1DB01.ORA E:\ORANT\DATABASE\DB01\USR1DB01.ORA E:\ORANT\DATABASE\DB01\TMP1DB01.ORA E:\ORANT\DATABASE\DB01\INDX1DB01.ORA 5 rows selected. SVRMGR>


Listing 1.10: Abfrage der Datenfiles mit Hilfe der View v$datafile

SVRMGR> connect internal/oracle Connected. SVRMGR> select member from v$logfile; MEMBER -----------------------------------------------E:\ORANT\DATABASE\DB01\LOGDB011.ORA E:\ORANT\DATABASE\DB01\LOGDB012.ORA 2 rows selected. SVRMGR>
Listing 1.11: Ermittlung der Log-Dateien durch Abfrage der View v$logfile

Nachdem Sie nun alle Dateien kennen, knnen Sie die Datenbank zusammen mit der Instanz herunterfahren; hierzu haben Sie in den beiden vorhergehenden Kapiteln gengend Beispiele kennen gelernt. Als Nchstes mssen Sie dafr sorgen, dass die Instanz nebst Datenbank beim nchsten Durchstarten des Rechners nicht wieder hochgefahren wird, indem Sie eventuell vorhandene Bootskripts kontrollieren. Unter NT mssen Sie im nchsten Schritt die zugehrigen Diensteintrge aus der Registrierungsdatenbank entfernen. Hierzu knnen Sie brigens auch das Programm ORADIMxx.EXE verwenden:
oradim80 -delete -sid db01 oradim80 -delete -srvc OracleStartDB01

Der erste Aufruf des Programms entfernt den zur Instanz gehrenden Diensteintrag (OracleServiceDB01) und der zweite Aufruf entfernt den Dienst, mit dem Sie die Datenbank automatisch ffnen konnten. Nun ist nur noch Datenmll brig, d.h. Sie knnen im letzten Schritt alle zugehrigen Dateien lschen.

1.7

Der Oracle Storage Manager

Whrend der Erstellung der DB01-Datenbank (vgl. Kap. 1.5.3) haben Sie gesehen, wie man mit Hilfe spezieller SQL-Befehle Tablespaces, Datenfiles oder Rollback-Segmente anlegt. Dieses Verfahren, eventuell notwendige Strukturnderungen mit Hilfe geeigneter Skripts durchzufhren, entspricht brigens oftmals der gngigen Praxis fr produktive Datenbanksysteme. Die einzelnen Skripte werden hierbei archiviert, so dass man bei Bedarf, z.B. nach einem Rechnercrash oder fr den Auf-

Der Oracle Storage Manager

93

bau eines Backup-Systems, eine exakt gleich konfigurierte Datenbank nahezu automatisch generieren kann, indem nach dem Erstellskript einfach auch alle nderungsskripts nacheinander eingespielt werden. Wie Sie im letzten Kapitel erfahren haben, ist aber nicht nur die Erstellung der Speicherobjekte via SQL mglich, sondern auch die Abfrage der vorhandenen Objekte mitsamt ihren Eigenschaften ist mit Hilfe spezieller Views mglich. Sofern Sie allerdings unter Windows arbeiten, dann gibt es aber mittlerweile fr nahezu jegliche Aufgabenstellung auch ein entsprechendes Tool mit grafischer Oberflche. Oracle8 Storage-Manager Zwecks Analyse oder Bearbeitung der Datenbankstruktur finden Sie hierzu in der klassischen 8er-Version den Oracle Storage Manager (VAG.EXE, vlg. Abb. 1.56), der im Rahmen des Oracle Enterprise Managers auf Ihrem Rechner installiert wird.

Abbildung 1.56: Der Oracle Storage Manager

Im weiteren Verlauf des Workshops werden Sie noch weitere hnliche Werkzeuge kennenlernen, d.h. die verschiedenen Tools haben einen hnlichen Aufbau, funktionieren sehr hnlich, unterscheiden sich aber durch ein jeweils spezielles Einsatzgebiet. Im linken Teil des Fensters finden Sie immer eine bersicht der vorhandenen Objekte. Wenn Sie eines dieser Objekte markieren, dann erhalten Sie im rechten Teil ein Fenster mit einem oder mehreren Registerkrtchen, in denen Sie die vorhandenen Eigenschaften des markierten Objekts betrachten oder ndern knnen.

94

Oracle erste Schritte

Im letzteren Fall knnen Sie die neuen Einstellungen mit Hilfe der Apply-Schaltflche speichern bzw. aktivieren oder Sie verwenden die Schaltflche Show SQL, um ein Fenster mit den zugehrigen SQL-Befehlen zu erhalten. Ein Programm mit Trainerqualitten also. Ansonsten denke ich, dass uns die Bedienung des Programms als mittlerweile Explorer und Windows gewhnten Anwender, keine greren Schwierigkeiten bescheren sollte. In der links dargestellten bersichtsliste knnen Sie brigens auch mit der rechten Maustaste agieren. Das ist hilfreich, wenn Sie neue Objekte anlegen oder vorhandene kopieren bzw. lschen wollen. Damit bin ich mit meinen Ausfhrungen zu diesem Werkzeug auch schon fast am Ende. Bemerkenswert ist lediglich noch eine besondere Funktionalitt, die dieses und alle weiteren Manager-Werkzeuge besitzen. Mit Hilfe des Eintrags Record aus dem Log-Men haben Sie die Mglichkeit, alle Ihre Aktivitten aufzuzeichen, d.h. hierbei werden die zugehrigen SQL-Kommandos protokolliert. Damit ist die Brcke geschlossen, zum einen die notwendigen Arbeiten mit Hilfe eines grafischen Tools komfortabel erledigen zu knnen und zum anderen alle nderungen in Form eines SQL-Befehlsskripts aufzuheben bzw. zu archivieren. Whlen Sie den Eintrag Stop aus dem Log-Men, um die Aufzeichnungsaktiviten zu beenden, wobei Sie jetzt die Mglichkeit erhalten, das Protokoll unter einem beliebigen Namen zu speichern. Probieren Sie das Ganze doch einfach mal aus. Wie Sie sich vielleicht erinnern, haben wir beim Anlagen der DB01-Datenbank im Rahmen der Nachbearbeitung das Rollback-Segment SYSROL angelegt. Dabei wurde dieses Segment am Ende der Verarbeitung inaktiviert, so dass es jetzt eigentlich gelscht werden knnte. Fhren Sie diese Aktion mit Hilfe des Storage Managers durch. Da wir aber wissen wollen, welche SQL-Anweisung sich dahinter verbirgt, schalten wir vorher die Protokoll-Funktion ein. Danach markieren Sie das Rollback-Segment SYSROL, drcken anschlieend die Taste (Entf), oder whlen im Kontext-Men (rechte Maustaste) den Eintrag Remove oder Sie verwenden den gleichen Eintrag im Rollback-Men. Besttigen Sie jetzt alle erscheinenden Sicherheitsabfragen, so dass das Segment aus der Datenbank entfernt wird. Anschlieend beenden Sie die Protokollierung mit Hilfe des Log-Mens und Speichern das Protokoll unter irgendeinem Namen ab. ffnen Sie jetzt das Protokoll mit einem beliebigen Texteditor, um den zugehrigen SQL-Befehl abzulesen:
DROP ROLLBACK SEGMENT "SYSROL"

Storage-Manager fr Oracle8i Mit der Version 8i wurden verschiedene Administrationsprogramme zum Oracle DBA Studio zusammengefasst, wobei Sie auch die Funktionen des Storage-Managers im DBA Studio (vgl. Abb. 1.57) wiederfinden. Mann kann sich das im Prinzip so vorstellen, dass der jeweils links im Bild angezeigte Baum um weitere Bltter erweitert wurde, die fr die jeweils unterschiedlichen Administratorwerkzeuge stehen. Konkret verbergen sich die Storage-Funktionalitten unter dem Eintrag Speicher und was Sie von dort aus aufklappen knnen, ist vllig identisch mit der in Abbildung 1.56 gezeigten Struktur.

SQL*Plus

95

Abbildung 1.57: Storage Manager im neuen Gewand des DBA Studios

Ich denke, dass man auch hier eigentlich kein Wort ber die prinzipielle Bedingung des Programms verlieren muss, wobei ich einmal anmerken mchte, dass mir persnlich die neuen 8i-Oberflchen sogar besser gefallen. Sie finden im DBA Studio in Bezug auf das Speichermanagement alle Funktionen wieder, die Ihnen bisher vom Storage Manager geboten wurden. So richtig neu ist eigentlich nur die Artund Weise, Ihre Arbeit gegebenenfalls in einem Protokoll zu speichern. Im Unterschied zum Storage Manager verfgt das DBA Studio ber ein permanentes Protokoll aller ausgefhrten SQL-Anweisungen, d.h. Sie finden hier auch eine Aufzeichnungen aller Abfragen, die das Programm zur Anzeige der einzelnen Objekte und deren Eigenschaften absenden muss. Sie erhalten dieses Protokoll, indem Sie im Ansicht-Men den Eintrag SQL-Historie der Anwendung auswhlen. Hierdurch erhalten Sie ein Fenster, indem alle vom Programm abgesetzten SQL-Anweisungen angezeigt werden. Ich finde das ist wirklich eine tolle Sache und ermglicht Ihnen den einfachen Zugriff auf viele technische Informationen Ihrer Oracle-Datenbank.

1.8

SQL*Plus

Wie Sie schon gesehen haben, bentigt man zum Arbeiten mit einer Datenbank, neben den eigentlichen Anwendungsprogrammen (z.B. PeopleSoft oder SAP), oftmals ein Werkzeug, mit dem man SQL-Befehle abschicken und die entsprechenden

96

Oracle erste Schritte

Ergebnisse empfangen kann. Am Beispiel des Server-Managers haben Sie bereits ein solches Werkzeug, einen SQL-Editor, kennengelernt. Allerdings macht es meistens wenig Spa, die Erstellung von Abfragen oder die Entwicklung von SQL-Programmen im Serverraum durchzufhren. Zwar hindert die Pelzmtze nicht unbedingt bei der Arbeit, aber mit dem Fustlingen aus dem letzten Skiurlaub kann man halt doch nur schlecht tippen. Wir bentigen also ein hnliches Werkzeug, das nicht auf die Ausfhrung auf dem Datenbankserver beschrnkt ist, sondern das wir an unseren normalen Arbeitsplatz benutzen knnen. Wer die Wahl hat, hat die Qual, denn Oracle bietet hierfr mal wieder gleich mehrere verschiedene Mglichkeiten. Beginnen wir zunchst mit dem Klassiker, den Sie im Rahmen der gewhnlichen Installation des Oracle-Clients erhalten. Wie Sie der berschrift entnehmen knnen, meine ich hiermit das Programm SQL*Plus, das je nach Betriebssystem und Installation als PLUS80.EXE, PLUS80W.EXE, SQLPLUSW.EXE oder lediglich SQLPLUS vorliegt. ber Geschmack kann man bekanntlich streiten und in Bezug auf dieses Tool gibt es, zumindest nach meiner Erkenntnis, wirklich genau zwei Lager: entweder man liebt oder hasst es (ich gehre eher zur zweiten Gruppe). Aber lassen wir den Geschmack mal auen vor. Fr das etwas angestaubt wirkende Tool gibt es in jedem Fall eine Daseinsberechtigung, denn im Unterschied zum spter beschriebenen SQL-Worksheet, finden Sie SQL*Plus in jeder Betriebsumgebung. Bentigen Sie beispielsweise auf einem AIX-Server einen SQL-Editor zum Abspielen eines Skripts, so ist das dank SQL*Plus berhaupt kein Problem. Tippen Sie innerhalb einer Telnet-Session das Kommando sqlplus ein, um den SQL-Editor zu starten (vgl. Abb. 1.58).

Abbildung 1.58: UNIX-Variante des SQL*Plus-Programms

Unter Windows heit das Programm der aktuellen 8er-Version PLUS80W.EXE (vgl. Abb. 1.59) und befindet sich blicherweise im /BIN-Unterverzeichnis der ClientInstallation. Das zugehrige Programm-Icon finden Sie in der Programmgruppe Oracle for Windows NT. Auch bei der Installation des 8i-Clients erhalten Sie

SQL*Plus

97

natrlich wieder ein SQL*Plus, wobei das Programm diesmal SQLPLUSW.EXE heit, sich diesmal aber berhaupt nicht von den bisherigen Windows-Varianten unterscheidet.

Abbildung 1.59: SQL*Plus unter Windows

Sie mssen zugeben, dass sich die beiden SQL*Plusse ziemlich hnlich sehen. In echt funktionieren Sie auch gleich, d.h. wer sich irgendwo mit SQL*Plus auskennt, kommt unter jeder Betriebsumgebung mit diesem Produkt zurecht; das ist sicherlich ein nicht zu vernachlssigender Vorteil. Falls Sie es auch unter Windows noch proprietrer mgen, dann knnen Sie SQL*Plus auch in einem MS-DOS-Fenster starten, in dem Sie dort das Programm PLUS80.EXE bzw. SQLPLUS.EXE beim 8iClient starten. Sie sehen also, warum so viele Installationsbeschreibungen immer noch auf SQL*Plus abstellen. Dieses Tool gibt es zum einen berall und funktioniert zum anderen immer gleich. Ansonsten gilt nicht nur bei Ikea: Entdecke die Mglichkeiten. Das Thema SQL*Plus ist so umfangreich, dass es hierzu in der OracleDokumentation sogar ein eigenes Buch SQL*Plus Users Guide and Reference gibt. Dort finden Sie in dem Kapitel Command Reference eine vollstndige bersicht der vorhandenen Befehle mit vielen Beispielen. Ich mchte im Rahmen dieses Buches nur einen berblick ber die vorhandenen Mglichkeiten geben und habe hierzu die nachfolgenden Hppchen ausgewhlt.

1.8.1

Abfragen eingeben und ausfhren

hnlich wie der Server-Manager arbeitet auch SQL*Plus zeilenorientiert, d.h. es erwartet Ihre Eingaben am Prompt (SQL>) und mit Hilfe der Eingabezeile erhalten Sie eine neue Zeile. Ihre Eingabe bzw. Zeilen werden innerhalb von SQL*Plus in einem internen Puffer zwischengespeichert und erst nach Abschluss Ihrer Eingaben an die Datenbank geschickt. Um die Eingabe abzuschlieen haben Sie verschiedene Mglichkeiten:

98

Oracle erste Schritte

: :

Sie beenden die Zeile mit einem Semikolon (;) und drcken danach die Eingabetaste. Hierdurch werden die im SQL-Puffer gespeicherten Befehle sofort an die Datenbank gesendet. Sie bettigen die Eingabetaste zweimal hintereinander. SQL*Plus beendet nmlich das Fllen des Puffers, wenn Sie in einer Leerzeile die Eingabetaste verwenden. Allerdings wird in dem Fall der Pufferinhalt nicht an den Server geschickt. Dies mssen Sie anschlieend noch durch Eingabe des Befehls run bzw. exec, wenn sich im Puffer ein PL/SQL-Programmblock befindet, veranlassen.

Der SQL-Puffer Erinnern Sie sich noch an Edlin oder arbeiten Sie regelmig mit UNIX-Systemen und kennen sich mit Befehlen wie ed oder vi bestens aus? Falls ja, dann willkommen Zuhause. Auch unter SQL*Plus stehen Ihnen hnliche zeilenorientierte Befehle zur Verfgung, um den im SQL-Puffer gespeicherten Text nachtrglich zu bearbeiten. So knnen Sie beispielsweise durch die Eingabe des Buchstabens l, den kompletten Inhalt des Puffers anlisten. Durch Eingabe eines i knnen Sie so lange weitere Zeilen am Puffer anfgen, bis Sie wieder zweimal Eingabe drcken und damit die Editierung beenden. Die wichtigsten Befehl zum Bearbeiten des SQL-Puffers knnen Sie der Tabelle 1.3 entnehmen:
Befehl a <Text> c /<alt>/<neu> c /<alt> cl buff del del <n> del <n> * del <n> <m> edit exec i i <text> l l <n> l <n> * l <n> <m> run Beschreibung fgt den spezifizierten Text am Ende der aktuellen Zeile an, vgl. auch Hinweise zu l <n>. ndert in der aktuellen Zeile den Text <alt> in den Text <neu>, z.B. c / fromm/from, um fromm in from zu ndern. lscht den Text <alt> aus der aktuellen Zeile. lscht den SQL-Puffer. lscht die aktuelle Zeile, vgl. zu l <n>. lscht die Zeile <n> aus dem SQL-Puffer. lscht den Puffer von der Zeile <n> bis zur aktuellen Zeile. lscht die Zeilen <n> bis <m> aus dem Puffer. ruft den per define_editor definierten Texteditor auf (vgl. nchsten Abschnitt). startet den im Puffer befindlichen PL/SQL-Block. fgt weitere Zeilen hinter der aktuellen Zeile des SQL-Puffers ein. fgt eine Zeile hinter der aktuellen Zeile eine neue mit dem Inhalt <text> ein. fhrt zur Anzeige des SQL-Puffers zeigt die Zeile <n> des SQL-Puffers an und macht diese zur aktuellen Zeile. zeigt den Puffer von der Zeile <n> bis zu aktuellen Zeile. listet die Zeilen <n> bis <m> aus dem Puffer. startet die im Puffer befindliche SQL-Anweisung.

Tabelle 1.4: SQL*Plus-Befehle zum Bearbeiten des SQL-Puffers

SQL*Plus

99

Verwenden eines Texteditors Dieses zeilenorientierte Editieren ist ehrlich gesagt nicht so nach meinem Geschmack. Da ist es schon gut, dass SQL*Plus den Inhalt des SQL-Puffers mit Hilfe einer temporren Datei, die standardmig den Namen AFIEDT.BUF besitzt, zwischenspeichern und zur weiteren Bearbeitung an andere Programme, vor allem Editoren, bergeben kann. Welchen Editor Sie hierbei verwenden mchten, knnen Sie durch ndern der Einstellung define_editor selbst festlegen:
define_editor=C:\Programme\pfe\PFE32.EXE

Wenn Sie anschlieend am SQL-Prompt den Befehl edit eingeben, dann setzt SQL*Plus das Kommando C:\Programme\pfe\PFE32.EXE AFIEDT.BUF in Form eines Kindprozesses ab, so dass in dem Beispiel der PFE-Editor zusammen mit der Pufferdatei wie ein modales Kindfenster von SQL*Plus erscheint. Nun, was will Ihnen der Autor hiermit sagen? So lange Sie das Fenster des Editors geffnet lassen, wird die SQL*Plus-Anwendung gesperrt, d.h. Sie knnen in SQL*Plus erst weiterarbeiten, nachdem Sie den Texteditor wieder geschlossen haben. Laden und Speichern von Dateien Unter Windows finden Sie im File-Men die Eintrge Open, Save und Save as, um eine als Datei gespeicherte Abfrage in den Puffer zu laden bzw. die dort zwischengespeicherten Anweisungen in einer Datei abzulegen. Je nach Betriebssystem besitzt die zugehrige SQL*Plus-Version ein solches Men aber gar nicht. Dennoch ist das Laden oder Speichern von Dateien in bzw. aus dem SQL-Puffer mglich, indem Sie am SQL-Prompt die Anweisungen get bzw. save verwenden:
get file_name [lis[t]|nol[ist]]

: :

file_name Geben Sie hier den Pfad und Namen der zu ladenden Datei ein. lis[t]|nol[ist] Mit dieser Zusatzoption knnen Sie vorgeben, ob die Datei nach dem Laden angezeigt wird (list = Standard) oder nicht (nolist).

sav[e] file_name [rep[lace]|app[end]]

: :

file_name Geben Sie hier den Pfad und Namen der zu speichernden Datei ein. rep[lace]|app[end] Standardmig versucht SQL*Plus die angegebene Datei zu erstellen. Ist die schon vorhanden, dann erhalten Sie eine Fehlermeldung und mssen dann die Option replace verwenden, um die Datei zu berschreiben. Mit der Option append wird der aktuelle SQL-Puffer an die vorgegebene Datei angehngt.

100

Oracle erste Schritte

1.8.2

SQL*Plus als Skriptinterpreter

Genau wie beim Server-Manager knnen Sie auch mit Hilfe von SQL*Plus sogenannte SQL-Skripte ablaufen lassen. In einem solchen Skript werden vielleicht verschiedene Abfragen oder spezielle SQL-Befehle ausgefhrt oder sogar komplexe PL/ SQL-Programme aufgerufen. Vielleicht verwenden Sie auf Ihrem Rechner ja auch gelegentlich oder sogar regelmig Batch-Dateien, um mit deren Hilfe regelmige Aufgaben, wie z.B.

: : : :

die Durchfhrung von Sicherungen, einen Dateiversand via FTP, das automatische Lschen bestimmter Dateien oder Verzeichnisse, oder sogar das sequentielle Starten verschiedener Programme

zu automatisieren. Die Befehle solcher Batch-Dateien werden eigentlich immer nicht direkt vom Recher bzw. dessen Betriebssystem, sondern immer mit Hilfe eines speziellen Kommandointerpreters, z.B. einem MS-DOS-Fenster unter NT, ausgefhrt. In Analogie hierzu knnen Sie SQL*Plus als Kommandointerpreter zur Oracle-Datenbank einsetzen. Hierzu knnen Sie SQL*Plus zusammen mit einem Skript starten, das dann automatisch ausgefhrt wird. Dieses Verfahren findet in der Praxis hufig Verwendung. Zum einen kann man hierfr spezielle Verknpfungen auf dem Desktop oder in einer Programm-Gruppe anlegen, um dann per Mausklick immer wiederkehrende Ablufe (z.B. Reorganisationsarbeiten, Fllen von Arbeitstabellen etc.) zu starten. Zum anderen finden Sie diese Methode aber in den Batchablufen von Produktionsumgebungen. Da werden im Rahmen der Nachtverarbeitung, gesteuert durch UNIX-Shell-Skripte, immer wieder verschiedene Abfragen oder PL/SQL-Programme gestartet. Zwischendurch laufen andere Programme wie zum Beispiel Datensicherungen oder andere Cobol- oder SQR-Anwendungen. Klar ist, dass in dem zuletzt genannten Beispiel die gesamte Verarbeitung auf dem UNIX-Server bleibt, was aufgrund der auch dort vorhandenen SQL*Plus-Version kein Problem ist. Kommanodzeilenparameter Um SQL*Plus in der eben beschriebenen Weise zu verwenden, mssen Sie das Programm zusammen mit verschiedenen Kommoandozeilenparametern verwenden. Diese Kommondozeilenparameter dienen vor allem zum Anmelden an die Datenbank bzw. zur bergabe des zu startenden SQL-Skriptes. Im Einzelnen knnen Sie hinter dem Programmnamen folgende Parameter verwenden:
[-s] [Logon] [Skript] [Argumente]

-s Dieser ruhige Modus sorgt dafr, dass zum einen das Fenster von SQL*Plus im Hintergrund bleibt und zum anderen in dem Fenster keine Meldungen ausgegeben werden. Dieser Modus ist damit vor allem geeignet, wenn Sie SQL*Plus aus

SQL*Plus

101

einem anderen Programm heraus starten und alle bentigten Anmeldeinformationen vorhanden sind. Logon Mit diesem Parameter mssen Sie die bentigten Anmeldeinformationen bergeben. Diese Anmeldeinformationen bestehen aus dem Benutzernamen, gefolgt von einem Schrgstrich (/) und dem zugehrigen Passwort und wird mit einem Klammeraffen (@) gefolgt von der Datenbankinstanz abgeschlossen (z.B. system/manager@db01). Dabei besteht auch die Mglichkeit, das Passwort wegzulassen, damit es nach dem Start von SQL*Plus abgefragt wird (z.B. system@db01). Skript Mit diesem Parameter knnen Sie das zu startende SQL-Skript vorgeben. Beginnen Sie Ihre Eingabe hierbei mit einem Klammeraffen (@) und spezifizieren Sie anschlieend das Skript mit geeignetem Zugriffspfad und Namen (z.B. @c:\temp\test.sql). Argumente Sofern Ihr Skript selbst weitere Argumente bentigt, dann knnen Sie diese jetzt vorgeben. Die im Skript verwendeten Platzhalter werden durch die bergebenen Argumente ersetzt. Dabei mssen Sie fr das erste Argument den Platzhalter &1 und fr alle weiteren Argumente die Platzhalter &2, &3 usw. verwenden.

Vervollstndigen wir diesen Abschnitt durch ein kleines Beispiel. Betrachten Sie hierzu zunchst das kleine nachfolgende Listing (1.12), das Sie auf der Begleit-CD im \SQLPLUS-Unterverzeichnis unter dem Namen PLUS01.SQL finden.
set termout off; spool &1; select name from v$datafile; spool off; set termout on; exit;
Listing 1.12: Beispiel fr ein kleines SQL*Plus-Skript

In dem Skript wird zunchst einmal mit Hilfe des Befehls set termout off die Ausgabe von Meldungen im SQL*Plus-Arbeitsfenster ausgeschaltet. Danach werden alle Ausgaben in die Datei &1 umgeleitet (spool). Da es sich hierbei um einen Platzhalter handelt, muss der konkrete Dateiname beim Start des Skripts als Argument bergeben werden. Danach erfolgt mit Hilfe der schon bekannten Abfrage die Ausgabe der Namen der zur Datenbank gehrenden Datenfiles. Zum Schluss wird die Ausgabeumleitung wieder aus- (spool off) und die Ausgabe im SQL*Plus-Fenster wieder eingeschaltet. Danach wird das Plus-Programm mittels Exit-Befehl beendet. Starten Sie nun, beispielsweise mit Hilfe des Ausfhren-Eintrags, aus dem WindowsStart-Men folgenden Befehl (vgl. Abb. 1.42):

102

Oracle erste Schritte

plus80w -s system/manager@db01 @c:\temp\plus01.sql c:\temp\ausgabe.dat sqlplusw -s system/manager@db01 @c:\temp\plus01.sql c:\temp\ausgabe.dat

Abbildung 1.60: Starten von SQL*Plus mit Parametern

Als Ergebnis dieses Aufrufs erhalten Sie in dem vorgegebenen Verzeichnis die Datei AUSGABE.DAT, in der Sie die Namen aller Dateibankdateien finden. Experimentieren Sie einfach mal mit den verschiedenen Startmglichkeiten, indem Sie beispielsweise mal den Schalter s weglassen. Variieren Sie auerdem die verwendeten Logon-Informationen, indem Sie zum Beispiel nur system@db01 verwenden, um die Passworteingabe nach dem Programmstart zu erzwingen. Benutzereingaben Manchmal kann es sinnvoll sein, whrend der Ausfhrung eines Skripts weitere Eingaben vom Anwender abzufragen. Ein prdestiniertes Beispiel hierfr sind Installationsskripte, in denen am Anfang verschiedene Installationsparameter abgefragt werden. Solche Eingaben knnen Sie zur Laufzeit mit Hilfe des AcceptBefehls vom Benutzer einfordern:
acc[ept] variable [num[ber]|char|date] [for[mat] format] [def[ault] default] [prompt text]

: : :

variable legt den Namen der Variable fest, in der die Eingabe gespeichert wird. Innerhalb des Skripts knnen Sie die Variable test ber die Zeichenfolge &test ansprechen. num[ber]|char|date Legen Sie hier bei Bedarf den Datentyp Ihrer Variablen fest. Wenn Sie nichts vorgeben, dann wird der Typ char angenommen. for[mat] format Legen Sie hier bei Bedarf das Format fr Ihre Eingabe fest. Bei Zeichenfolgen (char) haben Sie hierbei die Mglichkeit die maximale Lnge der Eingabe festzulegen, indem Sie als Format beispielsweise A10 fr eine maximal zehnstellige Eingabe verwenden. Bei Datums- oder Zeitwerten (date) knnen Sie das Eingabeformat mit Hilfe der Buchstaben DD (Tage), MM (Monate) und YY bzw. YYYY fr das Jahr (z.B. DD.MM.YYYY) oder HH24 (Zeit im 24-Stundenmodus), MI (Minuten) und SS fr die Sekunden (z.B. HH24:MI:SS) festlegen.

SQL*Plus

103

: :

Beim Eingabeformat numerische Werte legen Sie mit Hilfe der Ziffer 9 und dem Punkt (.) als Dezimaltrennzeichen vor allem wieder die maximale Lnge der Zahl bzw. die Anzahl der Nachkommastellen fest (z.B. 999.99). def[ault] default Legen Sie hier einen Standardwert fest, der genommen wird, wenn Sie die Eingabeaufforderung mit Hilfe der Eingabetaste bergehen. prompt text Geben Sie hier den Text ein, der whrend der Eingabeaufforderung am Bildschirm angezeigt wird.

Wir wollen nun unser kleines Beispiel erweitern, in dem wir die in einem vom Benutzer vorgegebenen Tablespace angelegte Tabellen ausgeben (vgl. Listing 1.13, PLUS02.SQL).
acc tname char format 'A20' default 'SYSTEM' prompt 'Name des Tablespace: '; set termout off; spool &1; select name from v$datafile; select table_name from dba_tables where tablespace_name = '&tname'; spool off; set termout on; exit;
Listing 1.13: Benutzereingaben whrend des Skripts abfragen

Am Anfang des Listings wird die Eingabe des Benutzers in der Variablen tname gespeichert, die etwas spter in einer Abfrage als &tname Verwendung findet. Mit Hilfe des Objekts dba_tables werden die Namen der Tabellen angezeigt, die in dem vorgegebenen Tablespace gespeichert sind; ansonsten entspricht das Beispiel der Datei PLUS01.SQL. Befehle des Betriebssystems verwenden Wie Sie mittlerweile wissen, knnen Sie SQL*Plus innerhalb eines Betriebssystemskripts verwenden, um eine Abfrage oder ein SQL-Programm zu starten. Das Ganze geht auch umgekehrt, d.h. Sie knnen innerhalb eines SQL-Skripts einen Betriebssystembefehl absetzen bzw. ein entsprechendes Skript starten. Testen Sie das doch gleich einmal und geben Sie am SQL-Prompt die folgende Anweisung ein:
ho[st] calc.exe

Hierdurch starten Sie aus SQL*Plus heraus den Windows-Taschenrechner. Genau wie beim Start des Editors wird das aufgerufene Programm hierbei wieder synchron aufgerufen, d.h. SQL*Plus wartet so lange mit der weiteren Ausfhrung der restlichen Zeilen im SQL-Puffer, bis das gestartete Programm wieder beendet wurde.

104

Oracle erste Schritte

Fr dieses Verfahren gibt es in der Praxis eine Menge Einsatzmglichkeiten. Zum Beispiel knnen Sie hierdurch das Kopieren oder den Ftp-Versand einer erstellten Ausgabedatei aus Ihrem SQL-Programm heraus veranlassen. Oder Sie verschicken automatisch ein E-Mail, nachdem Sie mit Hilfe verschiedener Abfragen eine spezielle Arbeitstabelle erstellt haben. Eine weitere Mglichkeit besteht in der Erstellung einer Datensicherung, bevor Sie eine komplexe nderungsabfrage starten, indem Sie zunchst den zugehrigen Tablespace inaktivieren und anschlieend die zugehrigen Dateien kopieren. Danach aktivieren Sie den Tablespace wieder und fhren Ihre nderungsabfragen durch. Hier und jetzt mchte ich diese Mglichkeit jedoch nur mit Hilfe eines einfachen Beispiels demonstrieren und hierzu das letzte Beispiel noch einmal ein wenig erweitern (vgl. Listing 1.14, PLUS03.SQL und 1.15, NACHLAUF.BAT).
acc tname char format 'A20' default 'SYSTEM' prompt 'Name des Tablespace: '; set termout off; spool &1; select name from v$datafile; select table_name from dba_tables where tablespace_name = '&tname'; spool off; set termout on; ho c:\temp\nachlauf.bat &1;
Listing 1.14: Starten der Batchdatei NACHLAUF.BAT

In dem Beispiel neu hinzugekommen ist lediglich die letzte Zeile mit dem ho bzw. host-Befehl. Dieses Kommando erlaubt den Aufruf eines beliebigen Betriebssystembefehls, also auch den Start einer ganzen Batch- bzw. Shellskripts. In unserem Beispiel wird die Batchdatei NACHLAUF.BAT, der beim Aufruf der Name der Ausgabedatei in Form des Parameters &1 bergeben wird.
echo jetzt luft die Batchdatei copy %1 c:\temp\protokoll.txt dir c:\temp rem ... beliebige weitere Kommandos pause
Listing 1.15: Ausdruck der Batchdatei NACHLAUF.BAT

In dieser Batchdatei knnen Sie natrlich alle mglichen Befehle des jeweiligen Betriebssystems verwenden. In unserem Beispiel verwenden wir verschiedenen DOS-Befehle, so dass Sie es ohne groe Anpassungen auf jedem Windows-Rechner verwenden knnen. Whrend der Ausfhrung wird die im SQL-Skript erstellte Ausgabedatei, die dem Batch als Parameter bergeben und dort mit Hilfe der Variablen %1 angesprochen werden kann, zur Datei PROTOKOLL.TXT kopiert. Am Ende wird die Batchausfhrung durch den Befehl pause angehalten, so dass das zugehrige MS-DOS-Fenster erst nach einem Tastendruck geschlossen wird, wonach Sie nach SQL*Plus zurckkehren.

Das SQL-Worksheet

105

1.9

Das SQL-Worksheet

Im Rahmen der Installation des Oracle Enterprise Managers erhalten Sie mit dem SQL-Worksheet einen weiteren SQL-Editor (vgl. Abb. 1.61 oder 1.62), der in der 8iVersion wieder in einem neuen Layout vorliegt. Zwar lsst dieser Editor ein komfortableres Bearbeiten von Programmen oder Abfragen zu, aber dennoch ist er kein vollstndiger Ersatz fr SQL*Plus, weil ihm vor allem die im Kapitel 1.8.2 beschriebenen Fhigkeiten fehlen, als Batchschnittstelle zwischen Datenbank und externen Ablufen zu fungieren.

Abbildung 1.61: Das SQL-Worksheet der 8er-Version

Nach dem Start des Programms erscheint zunchst ein kleines Fenster, mit dessen Hilfe Sie sich an einer Oracle-Datenbank anmelden knnen. Danach, d.h. nach erfolgreicher Datenbankanmeldung, erhalten Sie mit dem SQL-Worksheet im Prinzip zwei Fenster. Bei der 8er-Version dient das untere Eingabefenster als FullscreenEditor zum Eingeben bzw. Bearbeiten der bentigten Befehle und nach deren Ausfhrung werden die Ergebnisse im oberen Ausgabefenster dargestellt. In der 8i-Version ist das genau umgekehrt, d.h. im oberen Fenster wird getippt und im unteren geschaut. Die beiden Arbeitsfenster werden in der Mitte des Programmfensters durch eine Linie getrennt und sind standardmig gleich gro, wobei Sie deren Aufteilung mit Hilfe dieser Linie und der Maus beliebig verndern knnen.

106

Oracle erste Schritte

Abbildung 1.62: SQL-Worksheet im neuen 8i-Look

Der prinzipielle Umgang mit dem SQL-Worksheet sollte eigentliche berhaupt keine Probleme bereiten. Besondere oder verborgene Funktionalitten gibt es eigentlich nicht, deshalb mchte ich mich an dieser Stelle auch ziemlich kurz fassen. Alle Funktionen lassen sich entweder mit Hilfe des vorhandenen Mens oder der beispielsweise links unten bzw. oben sichtbaren Icons aufrufen. Besonders praktisch ist, dass das Ausfhren- bzw. Execute-Men mit der Funktionstaste F5 verknpft wurde, so dass Sie die erfassten SQL-Anweisungen quasi auf Knopfdruck starten knnen. Mit Hilfe der File- bzw. Datei-Meneintrge knnen Sie den Inhalt des Eingabefensters lschen, eine SQL-Datei in dieses Fenster hineinladen oder den aktuellen Inhalt speichern bzw. unter einem neuen Namen abspeichern. Besonders praktisch ist auch, dass die zuletzt ausgefhrten SQL-Anweisungen im SQL-Worksheet gepuffert werden und bei Bedarf jederzeit wieder mit Hilfe der Befehlshistorie wieder abgerufen werden knnen. Hierzu finden Sie im Worksheetbzw. Arbeitsblatt-Men entsprechende Meneintrge. Mit Hilfe des Clear All- bzw. Alles lschen-Eintrags aus dem Edit- bzw. BearbeitenMen knnen Sie den Inhalt des Eingabe- oder Ausgabefensters lschen. Welches Fenster hierbei gelscht wird, das hngt davon ab, in welchem der beiden Fenster Ihr Cursor stand bevor Sie den entsprechenden Meneintrag ausgewhlt haben. Klicken Sie also zunchst in das jeweilige Eingabe- oder Ausgabefenster und whlen

Das SQL-Worksheet

107

Sie danach den eben beschriebnen Meneintrag, um das Fenster bzw. seinen Inhalt zu lschen. Ich glaube, das waren genug Informationen, um mit der Arbeit des SQL-Worksheets problemlos zurecht zu kommen. Falls nicht, dann finden Sie in der Dokumentation des Oracle Enterprise Managers noch ein paar weitere Informationen.

2
2.1

Datenbankobjekte in einer Oracle-DB

Ich denke, dass ich kein groes Geheimnis lfte, wenn ich sage, dass Oracle genau wie zumindest auch alle anderen relationalen Datenbank seine Daten mit Hilfe von Tabellen speichert. Aber genau wie in den anderen Datenbanksystemen auch sind Tabellen natrlich nicht das Einzige, was Sie bei genauerem Hinschauen finden werden. In diesem Teil des Buches werden ich zunchst alle vorhandenen Datenbankobjekte kurz vorstellen bzw. erklren. Im weiteren Verlauf werden die fr unsere Beispieldatenbank bentigten Objekte angelegt und danach werden die auf der CD befindlichen Daten in die angelegten Tabellen geladen.

Der Oracle-Schema-Manager

Im Rahmen der Installation des Oracle Enterprise-Managers erhalten Sie ein Werkzeug, mit dem Sie alle verfgbaren Datenbankobjekte anlegen bzw. bearbeiten knnen. Es handelt sich bei der Version 8 hierbei um den Oracle Schema Manager (VAS.EXE), dessen Programmsymbol Sie blicherweise in der Programmgruppe Oracle Enterprise Manager finden (vgl. Abb. 2.1). Sofern Sie eine 8i-Datenbank verwenden, dann finden Sie die gleichen Funktionalitten jetzt im neuen DBA-Studio (vgl. Abb. 2.2). Nun kann man sich streiten, ob es sinnvoll ist, irgendwelche Datenbankdefinitionen mit Hilfe eines solchen Werkzeugs durchzufhren. Betrachten Sie einmal die Abbildung 2.1, in der das Fenster zum Bearbeiten des Programmcodes einer OracleDatenbankprozedur gezeigt wird. Ich glaube, man braucht nicht viel Phantasie um sich vorstellen zu knnen, dass der zugehrige Programmeditor in Form des kleinen Textfensters schon bei Programmen mit wenigen Zeilen alles andere als hilfreich ist.

110

Datenbankobjekte in einer Oracle-DB

Abbildung 2.1: bersicht der Objekte mit Hilfe des Oracle-Schema-Managers

Abbildung 2.2: Darstellung des Schema-Managers im DBA Studio der 8i-Version

Der Oracle-Schema-Manager

111

Des weiteren ist es in vielen Unternehmen nicht blich, Datenbankdefinitionen auf Basis manueller, nicht nachvollziehbarer und vor allem nicht automatisch wiederherstellbarer Einzelschritte durchzufhren. Entweder ist das konkrete Anwendungsprogramm aufgrund dort gespeicherter Definitionen in der Lage, die Datenbank mit Hilfe entsprechender SQL-Befehle oder eines generierten Skripts zu erzeugen oder die zur Erstellung der einzelnen Objekte bentigten Statements werden manuell in einem oder mehreren SQL-Skripts gesammelt. In jedem Fall hat diese Vorgehensweise gegenber der manuellen Erstellung ber den Schema Manager bzw. dem DBA-Studio den Vorteil, dass die gesamte Datenbank im Bedarfsfall automatisch generiert werden kann, indem beispielsweise einfach alle gesammelten Erstell- bzw. nderungsskripts nacheinander abgespielt werden. Trotzdem hat das hier kurz beschriebene Programm natrlich seine Daseinsberechtigung: Der Oracle-Schema-Manager bzw. das DBA-Studio bietet eine Visualisierung aller in der Datenbank enthaltenen Objekte. Dies ist unendlich komfortabeler, als sich beispielsweise alle Einzelheiten mit Hilfe diverser Abfragen aus den Systemtabellen herauszufummeln. Sie knnen das Programm als Hilfstrainer verwenden. Immer wenn Sie ein Objekt erstellen oder bearbeiten, finden Sie unterhalb des zugehrigen Dialogs die Schaltflche Show SQL bzw. SQL anzeigen, die Sie auch schon vom Oracle Storage Manager her kennen. Genau wie dort, fhrt zu einem Dialog, in dem Sie die zu Ihrer Erstellung oder nderung passende SQL-Anweisung finden. Nicht zu verachten sind auch die sich hinter der Help- bzw. Hilfe-Schaltflche verbergenden Informationen. Die zugehrige Online-Hilfe enthlt zeigt nmlich nicht lapidare Hinweise zur Programmbedienung, sondern erklrt die Ausprgungen der verschiedenen Eigenschaften des aktuell geffneten Objekts. Zur grundstzlichen Bedienung gibt es eigentlich nicht viel zu sagen, das Programm entspricht im Aussehen und in der Funktionsweise dem schon vorgestellten Storage Manager. Auerdem fhlen wir Windows-Explorer gewhnten Anwender uns gleich zu Hause: links der Baum, rechts die zum Blatt gehrenden Details. Ein letzter Hinweis zu dem Programm muss allerdings noch sein. Mit Hilfe der links im Bild befindlichen Liste werden alle Objekte katalogisiert, die in der zugehrigen Oracle-Datenbank mglich sind. Wundern Sie sich jedoch nicht, falls Sie im konkreten Fall mal weniger oder vielleicht auch mal mehr sehen. Die zur Verfgung stehenden Objekte hngen zum Teil nmlich von besonderen Zusatzfeatures ab, d.h. sie sind erst verfgbar, wenn Sie die entsprechenden Zusatzpakete installiert haben. Dies gilt vor allem fr die neuen objektorientierten Elemente, wie zum Beispiel die Array Types, Object Types oder Table Types. Sollten Sie die zugehrigen Kategorien in der bersicht Ihres Schema-Managers vermissen, dann mssen Sie nicht nach einem Installationsfehler suchen oder unbedingt nach einer neueren Version fahnden, denn sie sind nur dann verfgbar, wenn auf dem Datenbankserver die OracleObjekte installiert wurden, wobei es sich hierbei frher um ein extra zu beziehen-

112

Datenbankobjekte in einer Oracle-DB

des und damit meistens wohl auch kostenpflichtiges Erweiterungspaket handelte. Nach meinem Kenntnisstand sind die Objekte heute in aktuellen 8er-Versionen immer enthalten aber es gibt auch noch andere Features wie zum Beispiel Advanced replication oder Parallel Server, die nicht in jeder Version verfgbar sind. Fragen Sie im Zweifel direkt bei Oracle nach, wenn Sie gerade darber nachdenken eine eigene Oracle-Lizenz zu erwerben und unbedingt Wert auf die Objekt-Optionen legen. Ich werde dieses Feature im Rahmen der gleich folgenden Schema-bersicht abschlieend abhandeln, d.h. sowohl bei der Anlage unserer Musterdatenbank als auch in den noch folgenden Kapitel werden die vorgestellten Beispiele keine Objekte beinhalten. Auch wenn diese Features zum heutigen Stand zumindest fr ein Datenbanksystem beeindruckend sind, so spielen sie im Zusammenhang mit Standardsoftware im Augenblick noch keine Rolle. Solche Standardpakete nutzen meistens sowieso nur wenige spezielle Funktionen, da sie darauf ausgelegt sind, auf mglichst vielen unterschiedlichen Datenbanksystemen zu laufen. Aber zurck zum Thema. Wollen Sie nun ganz sicher gehen, ob Sie diese ObjektOption haben oder nicht, dann knnen Sie dies mit Hilfe einer Abfrage der View v$option klren:
SQLWKS> select * from v$option; PARAMETER ---------------------------------------------------------------Partitioning Objects Parallel Server Advanced replication Bit-mapped indexes Connection multiplexing Connection pooling Database queuing Incremental backup and recovery Instead-of triggers Parallel backup and recovery Parallel execution Parallel load Point-in-time tablespace recovery 14 rows selected.
Listing 2.1: Abfrage der installierten bzw. verfgbaren Optionen

VALUE -----TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE

Was ist ein Schema? Was ist berhaupt ein Schema? Ich habe den Begriff bisher selbst schon ein paar Mal verwendet, aber bisher noch nicht erklrt. Sofern Sie bisher nur mit anderen Datenbanksystemen gearbeitet haben, dann hren Sie diesen Begriff hier vielleicht zum ersten Mal, obwohl Sie das damit gemeinte Prinzip mit Sicherheit kennen. Hinter diesem Begriff verbirgt sich eigentlich nur die logische Zusammenfassung

Beschreibung der Objekte

113

von Datenbankobjekten wie Tabellen, Indizes oder Prozeduren zu einer Einheit, eben diesem sogenannten Schema. Technisch wird das in Oracle, wie brigens in den meisten anderen Datenbanken auch, durch einen speziellen Benutzer (engl. User) realisiert, dem alle zum Schema gehrenden Objekte gehren, also Eigentmer dieser Objekte ist. Aus technischer Sicht kann man also Schema und Benutzer gleichsetzen, d.h. wenn Sie im Rahmen einer Installationsanleitung lesen, dass Sie zunchst ein bestimmtes Schema anlegen mssen, dann ist damit die Anlage eines sicherlich meistens mit speziellen Rechten ausgestatteten Users gemeint, der Eigentmer der whrend der Installation anzulegenden Objekte wird. Oftmals handelt es sich bei einem solchen Schema um einen speziellen technischen Benutzer, d.h. mit Hilfe der zugehrigen Benutzer-Id wird nicht wirklich in der Datenbank gearbeitet, sondern diese Id dient nur zum Vorhalten der bentigten Datenbankobjekte oder wird auch zu deren Wartung bzw. nderung verwendet. Wenn man dieses Konzept durchhlt, dann entsteht zwangslufig eine gewisse Ordnung in der Datenbank. Dies gilt vor allem dann, wenn mehrere verschiedene Produkte in einer Oracle-Datenbank installiert wurden. Nehmen wir einfach mal an, die Tabellen und sonstigen Objekte der HR-Software PeopleSoft werden mit Hilfe des Benutzers psoft, die Objekte des Weiterbildungsprodukts Pisa unter Verwendung des gleichnamigen Benutzers und schlielich auch noch eine SAP-Anwendung, ber den User saphr installiert. Jedes dieser Produkte generiert fr sich zum Teil mehr als tausend verschiedene Datenbankobjekte, die allerdings wegen der drei unterschiedlichen Schematas jederzeit den einzelnen Anwendungen zugeordnet werden knnen. Betrachten Sie unter diesem Eindruck noch einmal das Bild des Schema-Managers (vgl. Abb. 2.1 oder 2.2). Die in der Datenbank vorhandenen Prozeduren werden mit Hilfe des links im Bild befindlichen Baums den jeweiligen Eigentmern, sprich dem Schema, zugeordnet, so dass eine sehr gute bersicht entsteht. Zum Schluss mchte ich noch auf ein weiteres kleines Schmankerl hinweisen, das dieses Schema-Konzept mit sich bringt. Nichts whrt fr die Ewigkeit, und so kommt irgendwann zwangslufig die Stunde, in der eine Anwendung gelscht werden soll, d.h. es mssen alle zugehrigen Objekte aus der Datenbank entfernt werden. Nichts einfacher als das, denn Sie mssen in dem Fall lediglich das entsprechende Schema, also den zugehrigen Benutzer, aus der Datenbank lschen. Hier gibt es nichts zu erben, d.h. mit dem Ableben des Besitzers verschwinden auch alle dessen Besitztmer.

2.2

Beschreibung der Objekte

Ich wei nicht, wie es Ihnen geht, aber ich bin immer froh, wenn ich beim erstmaligen Kontakt mit einer neuen Datenbank eine bersicht der vorhandenen Mglichkeiten finde, um rasch den Brckenschlag aus der alten in die neue Datenbankwelt hinzukriegen. Mit Mglichkeiten beschrnke ich mich hierbei natrlich auf die Fragestellung, was Sie alles in einer Oracle-Datenbank anlegen knnen. Auch

114

Datenbankobjekte in einer Oracle-DB

wenn eine solche bersicht zunchst immer nur einen oberflchlichen Eindruck hinterlsst, so hilft Sie dennoch, die folgenden ersten Gehversuche zu vereinfachen bzw. beschleunigen. Bestimmte Themen klassifiziert man sofort als wichtig und arbeitet sich folglich tiefer in die entsprechende Materie ein. Andere Themen bleiben im Hinterkopf und knnen bei Bedarf weitergehender erforscht werden. Mit Hilfe der folgenden Abschnitte will ich versuchen eine solche bersicht zu erstellen, in dem ich alle Objekttypen, die Sie mit Hilfe des Oracle Schema Managers erstellen knnen kurz beschreibe und auf die SQL-Befehle, die Sie zum Erstellen bzw. Bearbeiten der Objekte bentigen verweise, bzw. diese in den beschriebenen Beispielen verwende. Wie Sie im Verlauf des ersten Kapitels schon bemerkt haben drften, halte ich mich mit der Darstellung und Erklrung umfangreicher Syntax-Diagramme zu den einzelnen Oracle-Befehlen sehr zurck. Dies wird sich auch hier bzw. im weiteren Verlauf des Workshops nicht ndern. Die genaue Syntax eines Befehls knnen Sie mit all seinen Varianten am besten in den Unterlagen des Herstellers nachlesen und wrde in diesem Buch nur kostbaren Platz verbrauchen. Das grere Problem liegt zumindest nach meiner Erfahrung meistens darin, in Erfahrung zu bringen, welche Befehl einem bei dem aktuellen Vorhaben bzw. Problem weiterhelfen knnte. Kennt man erst einmal den Befehl, dann kann man die genaue Verwendung und Kodierung leicht mit Hilfe der Programmdokumentation nachschlagen. Weitergehende Informationen zur genauen Syntax bzw. Verwendung eines Befehls finden Sie in der Oracle-Dokumentation im Buch Oracle8 SQL Reference und tiefergehende Beschreibungen ber die Verwendung der einzelnen Objekte verbergen sich hinter dem Link Oracle8 Concepts. Bezglich der Programmierobjekte (Funktionen, Prozeduren und Trigger) finden Sie auch in diesem Buch, und zwar im fnften Kapitel Kapitel PL/SQL-Programmierung, weitergehende Informationen. Dort finden Sie neben weiteren Beispielen auch eine systematische Einfhrung in PL/SQL. Die nachfolgenden Beispiele (Listings) finden Sie alle auf der zum Buch gehrenden Begleit-CD. Sofern nichts anderes angegeben ist, dann finden Sie die Beispiele dieses Kapitels im \SCHEMA-Unterverzeichnis finden, wobei die Dateinamen den Listing entsprechend, d.h. die Datei fr das Listing 2.1 heit entsprechend LISTING21.SQL. Bei allen Beispielen mssen Sie natrlich beachten, dass Sie vor deren Anwendung spezielle individuelle Einstellungen wie beispielsweise Tablespacenamen berprfen und ggf. anpassen mssen.

2.2.1

Array-Typ (Array Types)

Wie ich schon eingangs erwhnt habe, handelt es sich hier um eine Kategorie, die Sie nur verwenden knnen, wenn auf Ihrem Datenbankserver die Objekt-Erweiterungen installiert wurden. Worum geht es aber nun bei diesen Array Types. Wenn Sie aus der Programmierung kommen, dann sagt Ihnen wahrscheinlich alleine schon der Begriff Array ziemlich deutlich, worum es hier geht. In deutschen bersetzungen spricht man in dem Zusammenhang meistens von Datenfeldern, und

Beschreibung der Objekte

115

damit wir alle ber das gleiche Sprechen, habe ich mal eine Definition des Begriffs Datenfeld ausgegraben: Datenfeld: Ein Satz aufeinanderfolgender, indizierter Elemente, die den gleichen Datentyp besitzen. Jedes Element eines solchen Feldes wird durch eine eindeutige Index-Nummer identifiziert. Wrde ich ein Buch zu einer Programmiersprache erstellen, dann htte ich zur Veranschaulichung des Arrays bzw. Datenfeldes vielleicht sogar den Begriff der Tabelle ins Spiel gebracht, aber Tabellen sind in einer relationalen Datenbank wirklich etwas ganz anderes. Mit Hilfe der Array Types haben Sie nun die Mglichkeit neue (eigene) Datentypen in Form von Datenfeldern zu definieren. Ein solcher selbstdefinierter Datentyp kann anschlieend innerhalb eines SQL-Programms, das alleine wre gar nicht so aufregend, und auch bei der Anlage von Tabellen verwendet werden. Beispiele Nehmen wir an, Sie mchten oder mssen eine Mitarbeitertabelle entwerfen, in der die individuelle Wochenarbeitszeit gespeichert werden kann. Da wir ja mittlerweile alle flexibel sind, reicht hierfr ein einfaches numerisches Feld zum Speichern der Wochenstundenzahl meistens nicht mehr aus. Stattdessen bentigen wir eher sieben numerische Felder, um die festgelegte Arbeitszeit pro Wochentag abzuspeichern (vgl. Listing 2.2).
drop table ma_arbeitszeit; / create table ma_arbeitszeit ( persnr varchar2(11) not null, sonntag number, montag number, dienstag number, mittwoch number, donnerstag number, freitag number, samstag number ) tablespace usr storage (initial 10000 next 10000 maxextents unlimited pctincrease 0) / commit;
Listing 2.2: Anlegen einer Tabelle zum Speichern der Wochenstundenzahl

Mit Hilfe einer solchen Tabelle knnten Sie nun fr jeden Mitarbeiter die individuelle Wochenarbeitszeit abspeichern. Betrachtet man nun die sieben Einzelfelder zum Speichern der Tagesstunden, so ist das gem der eben beschriebenen Definition ein erstklassiger Kandidat fr ein Datenfeld. Statt Sonntag, Montag, Dienstag

116

Datenbankobjekte in einer Oracle-DB

usw. sprechen wir dann nur noch von Tag(0), Tag(1), Tag(2), d.h. der Index des Tag -Datenfeldes legt den genauen Wochentag fest. Das Feature der Array Types ermglichen Ihnen nun genau ein solches Datenfeld anzulegen, indem Sie folgende Anweisung eingeben:
create type tag as varray(7) of number; / commit;
Listing 2.3: Anlegen des Datenfeld-Datentyps tag

Anschlieend knnen Sie die Arbeitszeittabelle dann mit Hilfe des nun folgenden Skripts definieren:
drop table ma_arbeitszeit; / create table ma_arbeitszeit ( persnr varchar2(11) not null, az_tag tag ) tablespace usr storage (initial 10000 next 10000 maxextents unlimited pctincrease 0) / commit;
Listing 2.4: Anlegen der Tabelle unter Verwendung des neuen Datentyps

Der wesentliche Unterschied zur vorhergehenden Version dieser Tabelle ist die Verwendung des neuen Datentyps tag anstelle der sieben numerischen Felder. Das hat natrlich Auswirkungen auf die Verwendung der Tabelle beim Einfgen oder nderung der dort gespeicherten Daten (CD: LISTING24A.SQL).
insert into ma_arbeitszeit values ('4711',tag(0, 7.5, 7.5, 7.5, 7.5, 7.5, 0)); insert into ma_arbeitszeit values ('4712',tag(0, 0, 9, 7.5, 7.5, 4.5, 2)); insert into ma_arbeitszeit values ('4713',tag(3, 7.5, 7.5, 0, 0, 0, 0)); commit; update ma_arbeitszeit set az_tag=tag(3, 7.5, 7.5, 4, 0, 0, 0) where persnr='4713'; commit;

Sowohl beim Einfgen neuer Datenstze als auch bei deren nderung mssen Sie fr das neue Feld az_tag das komplette Datenfeld vorgeben. Hierbei mssen Sie den Namen des Datentyps und danach alle Werte des Datenfeldes in Klammern und durch Komma getrennt spezifizieren.

Beschreibung der Objekte

117

Wollen Sie das Datenfeld jedoch im Rahmen eines SQL-Ausdrucks oder fr die Ausgabe innerhalb einer Auswahlabfrage verwenden, dann haben Sie allerdings noch ein kleines Problem, denn hierbei knnen Datenfelder nicht direkt eingesetzt werden, sondern Sie bentigen hierzu PL/SQL-Sprachelemente. In unserem Beispiel knnte wir als Abhilfe also eine kleine Funktion schreiben, mit der die gewnschten Elemente aus dem Datenfeld herauskopiert werden (vgl. Listing 2.5). Im Vorgriff auf das bernchste Kapitel soll die Funktion hier schon einmal erstellt werden.
create or replace function get_az(in_arr in tag, in_tag in number) return number is begin return in_arr(in_tag); end; / show errors; commit;
Listing 2.5: Erstellen einer Funktion zur Abfrage des Datenfeldes

Zur Funktion selbst mchte ich an dieser Stelle nicht allzu viel sagen. Im weiteren Verlauf dieses Streifzugs durch die Schema-Objekte der Oracle-Datenbank werden Sie weitergehende Hinweise ber die Erstellung und Verwendung von Funktionen finden. Das Problem war, dass Oracle beispielsweise im Rahmen des select-Befehls keine Datenfelder zulsst. Allerdings knnen Sie dort Funktionen verwenden und diese knnen wiederum Datenfelder als Parameter bernehmen, so dass wir unser Problem ber diesen Umweg lsen knnen. Insgesamt bergeben wir unserer Funktion get_az zwei Parameter. Der erste Parameter erwartet das Datenfeld und mit Hilfe des zweiten Wertes bergeben wir der Funktion den Index, fr den die Funktion den Wert aus dem Feld zurckliefern soll. Zur Vereinfachung verzichten wir innerhalb der Funktion auf jeglichen Komfort beispielsweise einer Wertebereichsprfung fr den bergebenen Index. Warum die direkte Verwendung des varray-Feldes im select-Ausdruck zu Problemen fhrt wird klar, wenn man sich einmal die Tabellenbeschreibung anschaut:
SQLWKS> desc ma_arbeitszeit Column Name Null? ------------------------------ -------PERSNR NOT NULL AZ_TAG Type ---VARCHAR2(11) RAW(192)

Wie Sie sehen, wird das Datenfeld intern mit Hilfe des Datentyps raw gespeichert. Normalerweise werden mit diesem Typ jegliche Binrdaten bzw. Bytekette wie zum Beispiel Grafiken oder Klnge gespeichert, d.h. die dort gespeicherten Daten sind in jedem Fall interpretationsbedrftig und damit nicht ohne weiteres anzeigefhig.

118

Datenbankobjekte in einer Oracle-DB

Schreiten wir also zur Verwendung unsere neuen Funktion und listen alle Mitarbeiter mit ihrer jeweiligen Dienstagsarbeitszeit an:
SQLWKS> select persnr, get_az(persnr, 2) from ma_arbeitszeit; PERSNR GET_AZ(PER ----------- ---------4711 7.5 4712 0 4713 7.5 3 rows selected.

Mit Hilfe des nchsten Abfragebeispiels suchen wir in unserer Tabelle Mitarbeiter, die am 12.07.2000 zumindest laut der vereinbarten Arbeitszeit anwesend sind:
SQLWKS> select persnr 2> from ma_arbeitszeit 3> where get_az(persnr, to_number(to_char(to_date('2000.07.12','YYYY.DD.MM'),'d'))) > 0; PERSNR ----------4711 4712 2 rows selected.

Diesmal verwenden wir unsere neue Funktion get_az innerhalb der where-Klausel der SQL-Abfrage. Das sieht zugegebener Weise auf den ersten Blick nicht so einfach aus, ist aber in Wirklichkeit gar nicht so schlimm wie es vielleicht scheint. Machen wir uns also die Mhe, und lsen die verwendete Schachtelfunktion einmal auf (vgl. Abb. 2.3).
get_az(persnr, 4) to_number(4) to_char(2000.07.12,'d') to_date('2000.07.12','YYYY.DD.MM') Abbildung 2.3: Entschachteln der verwendeten Funktionskette

Der innerste Funktionsaufruf verwendet die Standardfunktion to_date, um eine Zeichenfolge entsprechend der vorgegebenen Formatierung in ein Datum umzuwandeln. Dieses Datum erhlt die Standardfunktion to_char als Eingabeparameter und wandelt das Datum wieder in eine Zeichenkette um. Aufgrund des diesmal verwen-

Beschreibung der Objekte

119

deten Formatcodes erhalten wir hierbei den Tag der Woche (Sonntag = 0, Montag = 1 usw.), den wir der Funktion to_number als Eingabeparameter bergeben, und die das bergebene Zeichen als Zahl zurckliefert. Noch ein Hinweis: Bei der Anlage solcher Datenfelder knnen Sie nicht nur die standardmig in Oracle enthaltenen Datentypen (Zeichen, Zahlen, Datumswerte usw.), sondern auch alle selbstdefinierten Typen bzw. Objekte verwenden.

2.2.2

Cluster (Clusters)

Die sogenannten Cluster bieten in Oracle eine Methode zusammengehrige Daten in einem gemeinsamen Bereich, eben diesem Cluster, zu speichern. Die im Cluster gespeicherten Tabellen sollten also gemeinsame Spalten aufweisen, wobei als weiteres Kriterium hinzukommt, dass die Tabellen meistens auch zusammen gelesen werden. Letzteres ist der Fall, wenn die Tabellen immer wieder ber die gemeinsamen Felder verknpft werden oder mit Hilfe dieser Felder referentielle Integrittsbedingungen definiert wurden. Potentielle Kandidaten fr das Anlegen solcher Cluster sind damit Tabellen, die als Referenz in vielen andere Tabellen vorkommen. Technisch betrachtet stellt ein solcher Cluster zunchst einmal einen abgegrenzten Speicherbereich innerhalb eines vorhandenen Tablespaces dar und wird mit Hilfe der Anweisung create cluster erstellt bzw. mit alter cluster gendert und via drop cluster gelscht. Beim Anlegen der einzelnen Tabellen werden dann fr die gemeinsamen Daten zustzlich die zu verwendenden Cluster vorgegeben. Nehmen wir als Beispiel mal ein Abrechnungssystem und betrachten dort das Feld Kostenstelle. Dieses Feld ist zum einen der Primrschlssel der zugehrigen Tabelle Kostenstellen, in der die zugehrigen Stammdaten (Bezeichnung, Gltigkeit, Vorgesetzter usw.) gespeichert werden. Weiterhin enthlt auch der Mitarbeiterstamm eine Kostenstelle und auch in der Tabelle der Abrechnungsergebnisse ist eine Kostenstelle enthalten. Wird nun die Mitarbeiterkostenstelle ausgewertet, so bentigt man fast immer auch die Kostenstellentabelle selbst, um beispielsweise auch die Kostenstellenbezeichnung anzuzeigen oder die Auswertung nach Vorgesetzten zu sortieren. Zusammen mit der Kostenstelle werden die Tabellen Mitarbeiterdaten und Kostenstellen also meistens gemeinsam bentigt. Das Gleiche gilt auch bei den Abrechnungsergebnissen. Spielt hier bei einer Auswertung die Kostenstelle eine Rolle, dann bentigt man aus den eben genannten Grnden meistens auch noch die Kostenstellentabelle. Folglich knnte man in dem Fall einen Cluster fr das Feld Kostenstelle anlegen und anschlieend die drei Tabellen diesem Cluster zuordnen. Auch wenn man spontan einen anderen Eindruck bekommen knnte: Das Clustern von Tabellen hat keinen Einfluss auf deren sonstige Verwendbarkeit. Sie mssen also bei einer Abfrage nicht wissen oder bercksichtigen, ob eine Tabelle geclustert wurde oder nicht. Eine Gesamtbersicht ber die in der Datenbank vorhandenen Cluster erhalten Sie auer mit dem Schema-Manger oder DBA Studio durch eine Abfrage der View all_clusters.

120

Datenbankobjekte in einer Oracle-DB

2.2.3

Datenbank-Link (Database Links)

Wie Sie mittlerweile wissen, stellen verschiedene Oracle-Datenbanken selbst auf einem Rechnerknoten eigenstndige und voneinander abgeschottete Datensammlungen dar. In manch anderen Datenbanksystem ist das anders und entsprechend einfach ist es, beispielsweise innerhalb einer Abfrage auch Daten aus einer anderen, aber in dem DBMS registrierten, Datenbank zu verwenden. Dafr wird es meistens sehr viel schwieriger, wenn sich die bentigte Datenbank nicht auf dem gleichen Rechnerknoten bzw. unter Hoheit des gleichen DBMS befindet. Unter Oracle bentigen Sie fr den Zugriff auf eine weitere Datenbank immer eine Art Wegweiser, den Sie mit Hilfe der hier beschriebenen Datenbankverknpfung (Database Link) erstellen knnen. Dabei ist es dann allerdings gleichgltig, wo sich die bentigten Datenbank auf dieser Welt befindet. Einzige Voraussetzung ist, dass die bentigte Oracle-Datenbank ber das Net8-Netzwerk erreichbar ist (vgl. Abb. 2.4). Zwecks Anlage einer solchen Datenbankverknpfung bentigen Sie fr die Zieldatenbank eine geeignete Benutzer-Id nebst zugehrigem Passwort. Des weiteren muss auf dem Server der primren Datenbank ein Dienstname fr die Zieldatenbank existieren, beispielsweise mit Hilfe einer entsprechend konfigurierten Datei TNSNAMES.ORA. Der letzte Satz verdient noch einmal eine Verstrkung: der Client muss nicht in der Lage sein, sich selbst an die zu verknpfende Datenbank anzumelden, d.h. die Instanz, in der Client gerade arbeitet, stellt die Verbindung zu der verknpften Datenbank her. Wenn Sie MS-Access kennen, dann wissen Sie, dass Sie dort beispielsweise hnliche Mglichkeiten haben, indem Sie in der aktuellen Datenbank eine Tabelle aus einer anderen Datenbank einbinden bzw. verknpfen. So wie das Ganze in MS-Access wirklich den Namen Table Link verdient, beschreibt der hier verwendete Begriff Database Link zutreffend, worum es sich bei Oracle handelt, nmlich um ein universelles Tor zu einer anderen Datenbank. Bleiben wir bei diesen Bildern. Das per Link geffnete Tor zur fremden Welt (Datenbank) kann zwar in der Tat recht universell sein, aber es ist in jedem Fall auch recht schmal. Damit will ich sagen, dass Sie bei datenbankbergreifenden Abfragen die Ausfhrungsgeschwindigkeit ein wenig im Auge behalten sollten, doch hierzu erfahren Sie erst am Ende des dritten Kapitel mehr. In dem skizzierten Beispiel der Abbildung 2.4 ist der Client ber das Netzwerk mit dem Server Frankfurt verbunden und hat ber das Net8-Netzwerk Zugriff auf die dort laufende Datenbank einkauf, wobei er hierfr den in seiner Konfigurationsdatei TNSNAMES.ORA definierten Dienstnamen eink verwendet. Mehr Dienstnameneintrge hat der Client nicht, d.h. die Vertriebsdatenbank in Mnchen ist fr ihn direkt nicht erreichbar.

Beschreibung der Objekte

121

Client

connect hugo@eink select * from ver_mitarb@ein2

Netzwerk

Mnchen
Datenbank: vertrieb

Frankfurt
Datenbank: einkauf
Link ein2 = ver0

vert

eink

ver0.world = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP) (HOST = muenchen)) (CONNECT_DATA = (SID = vert)))

Abbildung 2.4: Verwenden von Datenbankverknpfungen

Auf dem Frankfurt-Server ist ebenfalls eine TNSNAMES-Konfiguration gespeichert. Mit Hilfe dieser Konfiguration wird der Dienstname ver0 definiert, der auf die Datenbankinstanz vert auf dem Server Muenchen verweist. Auerdem existiert in der Datenbank einkauf ein Link mit dem Namen ein2, der den Zugriffspfad zu irgendeiner Datenbank mit Hilfe des Dientsnamens ver0 beschreibt. Zugegeben, die in dem Beispiel verwendeten Krzel sind ein wenig abenteuerlich. In der Praxis htte man sowohl fr den Linknamen als auch fr den Dienstnamen auf dem Server sicherlich die Zeichenfolge vert verwendet, um den Zugriff transparent zu gestalten. Aber dann htten Sie nicht auf einem Blick gesehen, wie die Zusammenhnge sind. So aber ist ziemlich klar, welche Mglichkeiten Sie bei der Namensgebung haben und was wie heien darf bzw. was wie heien muss. Innerhalb einer Abfrage werden nun alle Tabellen, die mit Hilfe dieses Links aus der angebundenen Datenbank verwendet werden sollen, mit einem Klammeraffen (@) und dem Linknamen erweitert (z.B. select ... from xxxx@ein2). Erstellt werden solche Datenbankverknpfungen mit Hilfe des Befehls create database link, und mit Hilfe der Anweisung drop database link kann eben beschriebene Verbindungstr wieder geschlossen werden. Welche Mglichkeiten das Tor zur Abfrage der entfernten Tabellen wirklich bietet, hngt vor allem davon ab, mit welchem Benutzer sich die Datenbankinstanz an der Zieldatenbank anmeldet. Dieses Verfahren mssen Sie beim Erstellen des Links festlegen. Hierbei knnen Sie beispielsweise eine feste Benutzer-Id mit Passwort vorgeben oder der Zugriff soll mit dem Benutzer nebst den zugehrigen Rechten erfolgen, der die Abfrage mit dem Link ausfhrt.

122

Datenbankobjekte in einer Oracle-DB

Beispiele Wenn Sie Lust auf ein Beispiel haben und entsprechend dem ersten Kapitel die Datenbanken orcl und db01 besitzen, dann knnen Sie das eben Beschriebene leicht einmal ausprobieren und zwischen den beiden Datenbank einen Verknpfung erstellen. Erweitern Sie hierzu zunchst auf dem Server die Dienstnamenkonfiguration TNSNAMES.ORA um folgenden Eintrag:
orcl-l.world = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP) (HOST = ray_dell) (PORT = 1521) ) (CONNECT_DATA = (SID = orcl) ) )
Listing 2.6: Erweitern TNSNAMES.ORA fr den Database Link

Hierdurch erstellen Sie den Dienstnamen orcl-l, der fr den Zugriff auf die OrclInstanz genutzt werden kann. Melden Sie sich anschlieend als Administrator (Benutzer-ID system oder internal) an der Datenbankinstanz db01 an, und geben Sie dort folgende Anweisung ein:
create database link oralink connect to system identified by manager using 'orcl-l'; commit;
Listing 2.7: Erstellen des Database Links oralink

Dieser Befehl erstellt die Datenbankverknpfung mit dem Namen oralink und weist diese an, ber den Dienstnamen orcl-l eine Verbindung als Benutzer system mit dem Passwort manager aufzubauen. Der commit-Befehl in der zweiten Zeile schliet diese Transaktion ab, wodurch der neue Link verfgbar wird. Geben Sie nun die folgende Abfrage (Listing 2.8) ein, um Informationen ber die Struktur der entfernten Datanbank zu erhalten.
SQL> select name from v$datafile@oralink; NAME ----------------------------------------------------E:\ORANT\DATABASE\SYS1ORCL.ORA E:\ORANT\DATABASE\USR1ORCL.ORA E:\ORANT\DATABASE\RBS1ORCL.ORA E:\ORANT\DATABASE\TMP1ORCL.ORA SQL>
Listing 2.8: Abfrage der Dateinamen der orcl-Datenbank

Beschreibung der Objekte

123

Mit Hilfe einer Abfrage der View all_db_links knnen Sie sich brigens eine bersicht aller in der Datenbank definierten Datenbanklinks erzeugen.

2.2.4

Funktion (Functions)

Wenn Sie schon einmal mit einer moderneren Programmiersprache oder mit einer Tabellenkalkulation wie zum Beispiel MS-Excel gearbeitet haben, dann ist Ihnen die Verwendung einer Funktion sicherlich vertraut. Funktionen stellen blicherweise spezielle Miniprogramme zur Verfgung, mit deren Hilfe Sie bestimmte Aufgaben erledigen knnen. Dabei werden diese Funktionen blicherweise mit einem oder mehreren Parametern aufgerufen und liefern als Ergebnis genau einen Wert zurck. Auch innerhalb einer relationalen Datenbank spielen Funktionen heute eine wichtige Rolle. Eigentlich jeder ernstzunehmende Vertreter dieser Datenbankgattung stellt in seinem SQL-Sprachumfang eine umfangreiche Funktionssammlung zur Verfgung, mit deren Hilfe Sie verschiedene Aufgaben, wie zum Beispiel das Formatieren von Datumswerten, die Durchfhrung spezieller Berechnungen oder das Bearbeiten von Zeichenketten erledigen knnen. Des weiteren werden die bentigten Methoden der noch zu besprechenden Objekte mit Hilfe solcher selbstdefinierten Funktionen realisiert. So weit - so gut, doch eigentlich rede bzw. schreibe ich die ganze Zeit am eigentlichen Thema vorbei, oder einigen wir uns darauf, das ich mich nicht geradlinig, sonder kreisfrmig dem eigentlichen Kern der Sache nhere. Hier und jetzt geht es nmlich nicht um die Verwendung irgendwelcher vorgefertigten Programme, sondern unter Oracle haben Sie die Mglichkeit auch eigene Funktionen zu erstellen, deren sptere Verwendung sich in keiner Weise von den vom Hersteller gelieferten Vorbildern unterscheidet. Das ist eine Option, die zur Zeit in vielen anderen Datenbanksystemen noch ihresgleichen sucht. Eigene Funktionen werden in Oracle mit Hilfe des Schlsselwortes create function angelegt und mit Hilfe des Befehls drop function wieder gelscht. Um das Bearbeiten einer schon bestehenden Funktion zu vereinfachen, wurde die create-Anweisung um eine replace-Option erweitert, mit der Sie die bestehende Funktion ersetzen knnen. Diese Ersetzungsoption existiert im brigen fr viele Objekte und erspart Ihnen das bei vielen anderen DB-Systemen notwendige vorherige Lschen (droppen). Das hat unter Umstnden wiederum weitreichende Konsequenzen auf die Benutzeradministration, denn blicherweise gehen beim drop die individuell auf dieses Objekt zugewiesenen Rechte verloren, wohingegen sie beim replace erhalten bleiben, d.h. hinter dem replace steckt doch mehr als ein bisschen Benutzerkomfort dahinter. Beispiele Zur Demonstration wollen wir eine Funktion basteln, die den bergebenen Parameter anders formatiert zurckliefert. Konkret erwartet die Funktionen einen Text und liefert diesen rckwrts gelesen wieder zurck.

124

Datenbankobjekte in einer Oracle-DB

create or replace function spiegeln (in_c varchar2) return varchar is begin return '{' || in_c || '}'; end; / show errors; commit;
Listing 2.9: Erstellen eines einfachen Funktionsgersts

Betrachten Sie zunchst das Listing 2.9. Die hier gezeigte Funktion lst zwar nicht die eben beschriebene Aufgabenstellung, sondern sie demonstriert nur die Erstellung des bentigten und noch leeren Funktionsgersts. Beim Anlegen oder Bearbeiten von Funktionen mssen Sie hinter der create-Anweisung den Funktionsnamen, in unserem Fall spiegeln, angeben. Dahinter folgt in Klammern die durch Komma getrennte Aufzhlung der bergebenen Parameter nebst zugehrigem Datentyp. Hierbei knnen neben den vordefinierten Standarddatentypen (z.B. date, number oder varchar2) auch alle selbstdefinierten Typen verwenden. Nach dieser Parameterleiste folgt eingeleitet durch das Schlsselwort return die Definition des von der Funktion zurckgelieferten Datentyps und abschlieend leitet das Wrtchen is (oder as) die Beschreibung des eigentlichen Funktionsrumpfes ein. hnlich wie in Pascal, C und weiteren Programmiersprachen wird auch PL/ SQL blockorientiert kodiert. Solche Programmblcke beginnen mit dem Schlsselwort begin und enden mit einer end-Anweisung, wobei ein solcher Block auch immer mit einem Semikolon (;) abgeschlossen wird. Innerhalb eines solchen Blockes werden die einzelnen Anweisungen oder gegebenenfalls weitere Blcke kodiert, die ebenfalls durch ein Semikolon beendet werden. Wie schon gesagt, ist das Besondere an einer Funktion eben, dass sie einen berechneten Wert zurckliefert. Innerhalb des Funktionsrumpfes passiert dies mit Hilfe der Anweisung return. In unserem einfachen Beispiel folgt dieser Anweisung ein Ausdruck, mit dessen Hilfe der bergebene Ausdruck in geschweiften Klammern eingefasst wird. Dieses Einfassen erfolgt mit Hilfe des Operators ||, mit dem Sie Zeichenfolgen aneinanderhngen (konkatenieren) knnen. Nach der Kodierung der gesamten Funktion finden Sie in dem Beispiel noch die Verwendung der Anweisung show errors, bevor die ganze Transaktion mit Hilfe der commit-Anweisung abgeschlossen wird. Dieser Befehl tut eigentlich genau das, was er verheit, d.h. im Falle einer fehlerhaften Kodierung erhalten Sie hierdurch eine Anzeige der suspekten Programmstellen nebst zustzlicher Informationen. Nachdem Sie nun das Grundgerst einer Funktion kennen, wollen wir es im zweiten Schritt entsprechend der einstmals beschriebenen Aufgabenstellung erweitern (vgl. Listing 2.10).

Beschreibung der Objekte

125

create or replace function spiegeln (in_c varchar2) return varchar is out_c varchar2(254); i number; begin for i in reverse 1..length(in_c) loop out_c := out_c || substr(in_c, i, 1); end loop; return out_c; end; / show errors; commit;
Listing 2.10: Fertigstellung unserer spiegel-Funktion

Was hat sich nun im Einzelnen im Vergleich zum vorherigen Beispiel gendert? Zunchst einmal bentigen wir fr die Aufbereitung des rckwrts gelesenen Parameters eine Hilfsvariable, deren Inhalt wir am Ende der Funktion zurckliefern wollen. In dem Fall mssen Sie diese Variable gleich am Anfang, also noch vor dem ersten Programmblock, definieren. In unserem Beispiel verwenden wir hierzu die Variable out_c vom Typ varchar2 und mit einer maximalen Lnge von 254 Zeichen. Diese versteckte Definitionsanweisung wird genau wie jede andere auch mit einem Semikolon abgeschlossen. Innerhalb unsere Funktionsrumpfes definieren (deklarieren) wir zunchst eine weitere (numerische) Hilfsvariabel i. Hinter dieser Deklaration beginnt nun das eigentliche Programm innerhalb des zugehrigen Programmblocks. Wie Sie spter bei der PL/SQL-Einfhrung noch sehen werden, kann jeder Programmblock einen eigenen Deklarationsteil besitzen, der normalerweise durch das Schlsselwort declare eingeleitet wird. Bei der Anlage von Funktionen oder Prozeduren beginnt der Deklarationsteil direkt hinter dem Funktionskopf, also direkt hinter dem is-Schlsselwort. Aus diesem Grund muss die declare-Anweisung fr den ersten Programmblock weggelassen werden. Damit kennen Sie jetzt die grundstzliche Struktur einer jeden Funktion, egal, ob sie vor Ausfhrung des eigentlichen Programms eigene Variablen vorab deklariert oder nicht. Ein bisschen was gibt es allerdings noch zur Parameterleiste der Funktion anzumerken. Zwischen den dort spezifizierten Parameternamen und Datentypen knnen Sie bei Bedarf noch explizit festlegen, in welche Richtung die aufgezhlten Parameter verwendet werden knnen. Gewhnlich dienen solche Parameter immer als Eingangstor zu dem in der Funktion gespeicherten Programm, weshalb der Zusatz in dem Standard entspricht und daher weggelassen werden kann. Schematisch hat die Spezifikation eines Parameters folgenden Aufbau, wobei Sie eine Beschreibung der einzelnen Schlsselwrter in der Tabelle 2.1 finden:
<Parameter> in | out | in out <Datentyp>

126

Datenbankobjekte in einer Oracle-DB

Schlsselwort In Out in out

Bedeutung Standardwert der festlegt, dass der Parameter innerhalb der Funktion bzw. Prozedur nur gelesen werden kann. Das aufrufende Programm erwartet mit Hilfe dieses Parameters ein Ergebnis zurck. Der bergebene Parameter kann innerhalb des Programms gelesen aber auch gendert werden.

Tabelle 2.1: Festlegen der Verwendbarkeit von Parametern

Im eigentlichen Programm wird nun der bergebene Parameter mit Hilfe einer for..loop-Schleife durchlaufen. Diese Schleife zhlt wegen des Zusatzwortes reverse rckwrts beginnend von der Lnge der bergebenen Zeichenkette bis zur Zahl 1. Innerhalb der Schleife wird bei jedem Durchlauf die Zhlvariable i entsprechend gesetzt, so dass wir mit ihrer Hilfe und der Funktion substr das dem Durchlauf entsprechende Zeichen aus dem Eingabeparameter herausschneiden und an die Ausgabevariable out_c anhngen knnen.
SQLWKS> select parameter, spiegeln(parameter) from v$option; PARAMETER SPIEGELN(PARAMETER) ------------------------------------ -----------------------Partitioning gninoititraP Objects stcejbO Parallel Server revreS lellaraP Advanced replication noitacilper decnavdA Bit-mapped indexes sexedni deppam-tiB Connection multiplexing gnixelpitlum noitcennoC Connection pooling gniloop noitcennoC Database queuing gniueuq esabataD Incremental backup and recovery yrevocer dna pukcab latnemercnI Instead-of triggers sreggirt fo-daetsnI Parallel backup and recovery yrevocer dna pukcab lellaraP Parallel execution noitucexe lellaraP Parallel load daol lellaraP Point-in-time tablespace recovery yrevocer ecapselbat emit-ni-tnioP 14 rows selected.
Listing 2.11: Verwenden der selbstgeschriebenen spiegeln-Funktion

Natrlich knnen die in der Praxis verwendeten bzw. erstellten Funktionen wesentlich komplexer ausfallen, zum Beispiel weil die notwendigen Berechnungen umfangreicher als in unserer kleinen Funktion sind oder weil Sie von der Mglichkeit Gebrauch machen, innerhalb des Funktionsrumpfs weitere Datenbankabfragen auszufhren. Auf die zuletzt genannten Mglichkeiten werde ich in den nchsten Kapiteln noch hufiger zurckkommen. Verfolgen Sie einfach den im Anhang befindlichen Index, um diejenigen Seiten zu finden, auf denen die Verwendung der Funktionen weiter vertieft wird, womit wir die fast perfekte berleitung zur nchsten Kategorie des Schema-Managers gefunden haben.

Beschreibung der Objekte

127

2.2.5

Index (Indexes)

Bei einem Index handelt es sich um ein optionales Element, das zusammen mit Tabellen erstellt bzw. verwendet werden kann. Bei sachgemer Verwendung, knnen Sie die Ausfhrungsgeschwindigkeit von Abfragen erheblich erhhen, gleichgltig ob es sich hierbei um Auswahl- oder nderungsabfragen handelt. Dabei hat das Fehlen bzw. Vorhandensein eines Index keinerlei formale Auswirkungen auf die notwendige Kodierung der Abfrage. Letzteres gilt im Wesentlichen brigens fr nahezu alle marktblichen relationalen Datenbanksysteme, auch wenn der ein oder andere Vertreter die Mglichkeit bietet, im Rahmen einer Abfrage die Verwendung eines ganz speziellen Index zu erzwingen. Stellen Sie sich vor, Sie htten die Aufgabe, in diesem Buch jede Seite die den Begriff Funktion enthlt herauszusuchen. In dem Fall mssen Sie das gesamte Buch Seite fr Seite durchsuchen und dabei jede Seite markieren, in der Sie das gesuchte Wort finden. Das ist eine Aufgabe, fr die selbst gebte bzw. schnelle Leser mehre Stunden bis Tage bentigen. Ist fr dieses Wrtchen jedoch ein entsprechender Eintrag im Buchindex vorhanden, dann reduziert sich die fr diese Aufgabe bentigte Zeit auf wenige Sekunden. Zunchst mssen Sie das Wort im Index finden. Da dieser blicherweise sortiert ist, werden Sie hierbei sicherlich direkt beim Buchstaben F beginnen und erst danach die einzelnen Wrter so lange der Reihe nach durchgehen, bis Sie beim gesuchten Begriff Funktion angelangt sind. Anschlieend knnen Sie die zugehrigen Seitenzahlen ablesen und hierdurch die gesuchten Buchseiten direkt aufschlagen. Die eben beschriebene Vorgehensweise weist brigens verblffende Parallelen zu den von der Datenbank verwendeten Methoden auf. In diesem Workshop werden Sie im Kapitel Abfragen bei der Besprechung des Abfragetunings die Ausfhrungsplne des Datenbanksystems kennen lernen. Hier finden Sie Begriffe wie full table scan (ganzes Buch durchlesen), index scan (Begriff im Index nachschlagen), index range scan (im Index die Wrter Funk bis Funktion suchen) oder access per rowid (Buchseite direkt aufschlagen). Das Vorhandensein von den (richtigen) Indexeintrgen kann in einer Datenbank hnlich dramatische Auswirkungen haben. Ich selbst habe Situationen erlebt, wo das Lschen eines Index eine Abfrage bei sonst gleichen Bedingungen von 120 auf unter eine Sekunde beschleunigt hat, wodurch Sie sehen knnen, dass zu viele oder unsinnige Indices dem System auch schaden knnen. Ebenso ist es mir passiert, das die Ausfhrungsdauer einer verschachtelten nderungsabfrage durch das Anlegen eines Index von ber drei Stunden auf etwa zehn Sekunden reduziert werden konnte. Wie Sie sehen, reden wir hier also nicht ber Peanuts, sondern drehen in Bezug auf die Ausfhrungsgeschwindigkeit an einer zentralen Stelle der Datenbank. Wie aber kann ein Index besonders ntzlich oder schdlich sein? Diese Frage lsst sich pauschal leider nicht beantworten. Im Laufe der Zeit, d.h. bei entsprechender Erfahrung, werden Sie sicherlich ein gutes Gefhl dafr entwickeln, welcher Index fr welche Aufgabenstellungen hilfreich sein knnte. Die letztendliche Sicherheit erhlt man immer erst beim Testen der Abfragen zusammen mit entsprechend groen Tabellen und beim Studieren der zugehrigen Ausfhrungsplne.

128

Datenbankobjekte in einer Oracle-DB

Dennoch gibt es eine einfache Grundregel: Der Index soll helfen, die zugehrigen Stze in der Tabelle mglichst einfach zu finden. Das hrt sich banal an, ist es in der Praxis aber oft nicht. Um dies zu verdeutlichen, mchte ich noch einmal zu meinem eben beschriebenen Buchbeispiel zurckkehren. Nehmen wir einfach mal an, fr das zu durchsuchende Buch existiert ein Index, der neben den eigentlichen Suchbegriffen auch immer noch die beiden vorhergehenden und das nchste folgende Wort enthlt:
die neue Funktion ist, 1, 8 neben der Funktion wird, 9 zu der Funktion ist, 11

Wenn Sie dieses konstruierte Beispiel betrachten, dann sollte einleuchten, dass dieser Index nicht gerade zum schnellen Suchen und Finden einldt. In der Datenbankpraxis entsteht ein vergleichbarer Index, wenn bei der Erstellung mehrer Felder verknpft werden und der eigentliche Suchbegriff irgendwo in der Mitte der Kette der indizierten Felder auftaucht. Auerdem haben Sie die Mglichkeit, fr eine Tabelle mehrere verschiedene Indices fr unterschiedliche Felder bzw. Feldketten anzulegen und genau jetzt kann das zunchst latente Problem, denn ein schlechter Index ist oft immer noch besser als keiner, eskalieren, wenn aufgrund der Indexauswahl der eigentlich bessere nicht mehr verwendet wird. Neben dem Beschleunigen von Abfragen kann es noch weitere Grnde fr die Anlage eines Index geben. Nehmen wir einmal an, Sie mchten in einer Tabelle die Eindeutigkeit eines Feldes oder einer bestimmten Feldkombination erzwingen, ohne dass Sie je vorhaben, direkt nach diesem Feld bzw. der Kombination zu suchen. Trotzdem wre in dem geschilderten Fall die Anlage eines speziellen Index fr dieses Feld bzw. die Felder die Manahme der ersten Wahl. Wie Sie gleich noch sehen werden, existieren bei der Anlage eines Index verschiedene Varianten. Eine dieser Varianten ist die Erzwingung eindeutiger Indexeintrge, so dass bei dem Versuch des Einfgens von neuen Stzen, deren Felder bzw. Feldkombinationen diese Regel verletzen wrden, ein Fehler entsteht. Jede grere Tabelle sollte mindestens einen solchen eindeutigen Index besitzen, mit dessen Hilfe jede gespeicherte Reihe eindeutig identifiziert werden kann (Primrschlssel). Physikalisch wird ein Index unabhngig von der zugehrigen Tabelle gespeichert, wobei die Indices blicherweise sogar in einem eigenen Tablespace und damit in einem eigenen Datenfile und hierdurch vielleicht sogar auf einer eigenen Festplatte gespeichert werden. In Oracle knnen Indices explizit oder implizit angelegt werden. Im ersten Fall erfolgt die Anlage durch Eingabe einer entsprechenden create index-Anweisung bzw. die Lschung eines Index erfolgt mit Hilfe des Befehls drop index. Bei der impliziten Indexerstellung erfolgt die Definition zusammen mit der Tabellenbeschreibung, wobei wir uns diese Mglichkeit erst spter bei der Beschreibung der Tabellen anschauen werden. Eine abschlieende Bemerkung mchte ich noch machen, bevor wir das Ganze nun wieder an einem Beispiel ausprobieren. Wo viel Licht ist, da ist bekanntlich

Beschreibung der Objekte

129

auch ein wenig Schatten. Die hier in den Vordergrund gestellten Vorteile der Indices gibt es in einer Datenbank nicht kostenlos. Zum einen bentigen die Indices Plattenplatz und zum anderen kostet auch deren Verwaltung Rechnerressourcen. Schlielich muss das Datenbanksystem bei jeder nderung nicht nur die eigentliche Datentabelle, sondern auch alle Indices aktualisieren. Aus diesem Grund ist es verstndlich, dass in manchen Architekturen nur diejenigen Indices permanent verfgbar sind, die fr die Performance der Dialoganwendung vorteilhaft sind. Andere Indices, die fr bestimmte Batchlufe oder Reports vorteilhaft sind, werden erst bei Bedarf erstellt und am Ende des Batch-Programms bzw. des Reports wieder gelscht. Beispiele Bevor Sie irgendwelche Indices anlegen knnen, bentigen Sie logischerweise zunchst einmal eine Tabelle, die im Rahmen des folgenden Listings angelegt wird, wobei Sie das Beispiel in der Datei LISITING12A.SQL finden.
drop table mitarbeiter; / create table mitarbeiter ( persnr varchar2(11) not null, name varchar2(50), strasse varchar2(30), ort varchar2(30), plz varchar2(5) ) tablespace usr storage (initial 10000 next 10000 maxextents unlimited pctincrease 0) / commit; insert into mitarbeiter values ('4711', 'Raymans, Heinz-Gerd', 'Heinrichstr. 7','Duisburg','47231'); insert into mitarbeiter values ('4712', 'Schmidt, Harald', 'Duissernplatz 2','Dsseldorf','42231'); commit;

Nachdem Sie nun mit der Mitarbeitertabelle ein Demonstrationsobjekt haben, knnen Sie in einem zweiten Schritt einen Index anlegen (vgl. Listing 2.12).
create unique index mitarbeiter_pk on mitarbeiter (persnr) tablespace indx storage (initial 10000 next 10000 maxextents unlimited pctincrease 0); commit;
Listing 2.12: Index fr die Mitarbeitertabelle anlegen

In dem Beispiel legen Sie fr die Tabelle mitarbeiter einen eindeutigen Index fr das Feld persnr mit dem Namen mitarbeiter_pk an, der im brigen fr das gewhlte Schema eindeutig sein muss. Der Index wird in dem Tablespace indx gespeichert und erhlt eine eigene Storage-Klausel. Wenn Sie diese Speicherbelegungsregel

130

Datenbankobjekte in einer Oracle-DB

weglassen, dann wird stattdessen die bei der Anlage des Tablespaces spezifizierte Klausel verwendet. Versuchen Sie doch einfach mal nach Anlage dieses Indexes die oben abgedruckten Insert-Anweisungen noch einmal auszufhren. Da dies zu einer Verletzung der Indexeindeutigkeit fhrt, erhalten Sie folgerichtig den entsprechenden Hinweis unique constraint (SYSTEM.MITARBEITER_PK) violated, wobei die Datenstze nicht in die Datenbank eingefgt werden.

Varianten Index fr mehrere Felder Wenn Sie einen Index fr mehrer Felder erstellen mchten, dann mssen Sie diese einfach innerhalb der Klammer durch Komma getrennt aufzhlen. Solche zusammenhngenden Indices knnen maximal 32 Felder enthalten und sollten (vgl. Anmerkungen von oben) entweder einen sinnvollen Suchpfad wiedergeben oder in der vorgegebenen Kombination den Primrschlssel der Tabelle bilden:
create unique index mitarbeiter_p1 on mitarbeiter (persnr, plz)

Sortierung des Index festlegen Bei der Anlage eines Index knnen Sie dessen Sortierung festlegen, indem Sie hinter den einzelnen Spalten die Sortierreihenfolge mit Hilfe der Schlsselwrter asc (aufsteigend, standard) bzw. desc (absteigend) festlegen. Das kann sinnvoll sein, wenn die Daten oft entsprechend sortiert ausgegeben werden mssen.
create index mitarbeiter_pl on mitarbeiter (plz desc)

Nicht eindeutiger Index Lassen Sie das Schlsselwort unique weg, wenn Sie keinen eindeutigen Index erstellen mchten:
create index mitarbeiter_p2 on mitarbeiter (name)

Nicht wiederherstellbar Mit Hilfe der Option unrecoverable verhindern Sie, dass der Index bei der Protokollierung auf den Redo-Log-Dateien bercksichtigt wird. Diese Option ist allerdings ein Auslaufmodell und nur noch aus Kompatibilittsgrnden verfgbar. Verwenden Sie stattdessen das Schlsselwort nologging, wenn sie die Protokollierung fr den Index ausschalten wollen.
create unique index mitarbeiter_pk on mitarbeiter (persnr) tablespace indx nologging;

Weitere Varianten Die bisher beschriebenen Verfahren und Varianten sind diejenigen, die Ihnen zumindest nach meiner Erfahrung in der Praxis meistens ber den Weg laufen.

Beschreibung der Objekte

131

Daneben existieren noch ein paar exotischere Mglichkeiten, beispielsweise diejenige des Bitmap Index. Diese Anlageform, die allerdings nur in der Oracle Enterprise Edition verfgbar (vgl. Listing 2.1) ist, wandelt die spezifizierten Indexspalten in entsprechende Bitmuster um. Dieses Verfahren verspricht Performancevorteile bei Spalten mit geringen Wertebereichen (z.B. Geschlecht). Index verwalten Die explizit ber create index angelegten Indices knnen mit Hilfe der Anweisung drop index wieder aus der Datenbank entfernt werden, indem Sie den Befehl zusammen mit dem vergebenen Indexnamen verwenden.
drop index mitarbeiter_pk

Intern werden die Indices mit Hilfe sogenannter B*-Bume verwaltet. Damit diese Bume beim Suchen dauerhaft optimal funktionieren schadet es nicht, sie von Zeit zu Zeit zu reorganisieren. Hierzu ist es allerdings nicht notwendig den Index zu lschen und anschlieend neu anzulegen, sondern Oracle bietet zusammen mit der Anweisung alter index eine Variante, den spezifizierten Index neu aufzubauen (vgl. Listing 2.13).
alter index mitarbeiter_pk rebuild; commit;
Listing 2.13: Index reorganisieren

Einen berblick ber die in der Datenbank gespeicherten Indices erhalten Sie mit Hilfe einer Abfrage auf die Views all_indexes oder all_ind_columns. Die erste der beiden Views zeigt die generelle Definition des Index, d.h. hier erhalten Sie beispielsweise Informationen ber die Speicherbelegungsregel (storage-Klausel) oder den verwendeten Tablespace. Die zweite View zeigt den Aufbau des Index, d.h. sie liefert die Reihenfolge und Namen der im Index verwendeten Spalten. Vergleichen Sie hierzu die im Listing 2.14 abgedruckte Abfrage, in der diese beiden Views verknpft werden, um die Indices und deren Zusammensetzung fr die Tabelle mitarbeiter zu ermitteln; das Listing 2.15 zeigt Ihnen die zugehrige Ausgabe dieser Abfrage entsprechend den eben behandelten Beispielen.
select a.index_name, a.uniqueness, b.column_name from all_indexes a, all_ind_columns b where and and and a.owner='SYSTEM' a.table_name = 'MITARBEITER' b.index_owner = a.owner b.index_name = a.index_name

order by a.index_name, b.column_position


Listing 2.14: Analyse der Indexstruktur mit Hilfe vorhandener Systemviews

132

Datenbankobjekte in einer Oracle-DB

INDEX_NAME -----------------------------MITARBEITER_P1 MITARBEITER_P1 MITARBEITER_PK 3 rows selected.

UNIQUENES --------UNIQUE UNIQUE UNIQUE

COLUMN_NAME ---------------------PERSNR PLZ PERSNR

Listing 2.15: Abfrage der vorhandenen Indices entsprechend unserem vorhergehenden Beispiel

2.2.6

Objekttyp (Object Types)

Hinter dieser Kategorie verbirgt sich technisch auch wieder der Befehl create type, so dass Sie Ihnen auch diese Funktionalitten wieder nur zusammen mit der ObjekteOption (vgl. Array Types) zur Verfgung steht. Konkret geht es hier entsprechend der Kategorieberschrift in der Tat um die Definition sogenannter Objekte. Bei einem Objekt handelt es sich um eine Einheit, bestehend aus einer benutzerdefinierten Datenkomposition und einer Sammlung von Funktionen und Prozeduren, um diese Daten zum Bearbeiten oder weitergehenden Funktionalitten bereitzustellen. Im Zusammenhang mit einem solchen Objekt werden die gespeicherten Daten blicherweise als Attribute oder Eigenschaften bezeichnet, wohingegen man bei den Funktionen und Prozeduren, die in irgendeiner Weise das Verhalten des Objektes reprsentieren, von Methoden spricht. Natrlich wrde eine systematische Einleitung in den Objekt-Themenkomplex den Rahmen dieses Buches bei weitem sprengen. Ich glaube aber trotzdem, dass selbst wenn Sie bisher noch gar keine Erfahrung in objektorientierter Programmierung sammeln konnten, die nachfolgenden Ausfhrungen und Beispiele fr Sie nachvollziehbar sind und Klarheit in den einen oder anderen Aspekt des objektorientierten Ansatzes bringen werden. Ich bin immer wieder belustigt ber den manchmal stattfindenden Glaubenskrieg zwischen objektorientierter und klassischer rein prozeduraler Programmierung. Ich denke fr beide Anstze gibt es entsprechende Existenzberechtigungen. Was ich allerdings auch nicht mag ist, wenn in mancher Literatur in Bezug auf Objektorientierung der Eindruck entsteht, hierdurch wrde ich bertreibe mal ein wenig quasi ein neues Weltbild entstehen und die Einfhrung erfolgt mit Hilfe von derartigen Beispielen, dass man anschlieend glaubt, Objekte sind nur etwas fr ber den Dingen stehende Freaks. Die Welt ist die gleiche geblieben, es sind lediglich neue Verfahren und Werkzeuge zu deren Beschreibung hinzugekommen. Vor etwa fnfzehn Jahren habe ich mein erstes Cobol-Programm fr eine Dsseldorfer Versicherungsgesellschaft geschrieben. Fr alles und jedes gab es irgendwelche Strukturen, beispielsweise die Struktur Versicherungsnehmer, die aus den Komponenten Name, Strae, Ort, Geburtsdatum und vielen weiteren Felder bestand. Heute formuliert man anders, das Objekt Versicherungsnehmer verfgt ber die Eigenschaften Name, Strae, Ort usw., aber es hat sich eigentlich nichts gendert, denn es geht darum zusammengehrende Informationen geeignet zu bndeln.

Beschreibung der Objekte

133

Jeder Versicherungsnehmer verfgt bzw. besitzt beliebig viele Vertrge, mit zumindest gleichem Vertragsstamm. Heute beschreibt man das natrlich eleganter und ordnet dem Versicherungsnehmer eine Kollektion des Objekts Vertragsstamm zu. Bei der Arbeit mit diesen Strukturen war mein eigentlich permanent auf der Suche nach schon existierenden Unterprogrammen, beispielsweise einem solchen, das mit Hilfe der bergebenen Struktur die Anschrift oder die Anrede korrekt aufbereitet. Sptestens jetzt treten die Vorteile der Objektorientierung strker in den Vordergrund, denn hierbei sind Sie in der Lage, auch diese Verfahren an die Struktur bzw. das Objekt zu binden. Neben der Bndelung der Daten erfolgt also auch die Konzentration der bentigten Funktionalitten unter ein und demselben Begriff, eben diesem Objekt. Bei diesen Funktionalitten spricht man blicherweise von Methoden. In meinem Beispiel des Versicherungsnehmers erfolgt der Zugriff auf den Namen beispielsweise durch Kodierung der Anweisung
x = versicherungsnehmer.name versicherungsnehmer.name = Meier, Huber

und in Abhngigkeit davon, auf welcher Seite des Ausdrucks das Gleichheitszeichen steht, fragt man den Namen ab oder weist ihn zu. Mchte man die Anschrift formatiert ausdrucken, dann spezifiziert man jetzt vielleicht einfach nur noch folgende Anweisung:
print versicherungsnehmer.print_anschrift().

Beispiele Als Beispiel fr diesen Themenkomplex mchte ich das Objekt mensch erstellen. Damit das Beispiel bersichtlich bleibt, erhlt unser mensch-Objekt natrlich nur wenige Eigenschaften wie Namen, Anschrift und das Geburtsdatum. Entsprechend zurckhaltend gehen wir auch mit der Definition von Methoden um. Zum einen soll eine Methode zur Berechnung und Ausgabe des Alters, und zum anderen die eben beschriebene Funktion zur formatierten Anschriftenausgabe erstellt werden.
create or replace type mensch as object ( name varchar2(30), vname varchar2(30), strasse varchar2(30), plz varchar2(5), ort varchar2(30), geschl varchar2(1), gebdat date, member function g_alter return number, pragma restrict_references(g_alter, wnds, wnps), member function g_anschrift return varchar2,

134

Datenbankobjekte in einer Oracle-DB

pragma restrict_references(g_anschrift, wnds, wnps) ); / commit;


Listing 2.16: Erstellung unseres Objekts mensch

Zunchst legen wir mit Hilfe des schon bekannten Befehls create type das Objekt mensch an (vgl. Listing 2.16). Das funktioniert auf den ersten Blick ganz hnlich wie die Anlage einer Tabelle, denn die einzelnen Eigenschaften werden genau wie die Spalten einer Tabelle angelegt. Im zweiten Schritt werden die beiden Methoden g_alter und g_anschrift definiert. Dieser Teil erinnert wiederum sehr stark an die Anlage eines Packages und es macht durchaus Sinn, an dieser Stelle kurz zu unterbrechen und zunchst einmal den zu dem Schema-Objekt zugehrigen Abschnitt mitsamt dem Beispiel durchzuarbeiten. Dort finden Sie auch eine genaue Erklrung zu dem Compilerschalter restrict_references, mit der wir fr beide Funktionen festlegen, dass sie keine Datenbanknderungen durchfhren und keine globalen Variablen ndern knnen. Danach legen wir die Tabelle im nchsten Schritt zunchst einmal in der klassischen Form an (vgl. Listing 2.17).
drop table menschen; / create table menschen (xmensch mensch ) tablespace usr; commit;
Listing 2.17: Anlage der Tabelle menschen.

Klassisch heit hierbei, dass wir die Tabelle spaltenweise anlegen, wobei eine oder mehrere dieser Spalten halt zufllig aus einem selbstdefinierten Datentyp gebildet wird. Wie damals bei den Datenfeldern (varray) erhalten wir hierdurch einen abstrakten, interpretationsbedrftigen Datentyp und damit wieder Probleme oder zumindest Mehraufwand innerhalb von SQL-Ausdrcken. Aber auch beim Einfgen bzw. ndern von Daten mssen wir den Datentyp konstruieren oder jedes Mal entsprechende selbst zu programmierende Member-Funktionen verwenden.
SQLWKS> desc menschen Column Name Null? Type ------------------------------ -------- ---XMENSCH ADT(212)

Wie gesagt, bentigt man selbst beim Anlegen von Stzen einen entsprechenden Konstruktur. In Oracle kodiert man den durch Nennung des Datentyps, dem in Klammern eine Aufzhlung aller einzelnen Elemente folgt:

Beschreibung der Objekte

135

insert into menschen values ( mensch('Raymans', 'Heinz-Gerd', 'Harmoniestr. 2a', '47302', 'Duisburg', 'M', to_date('1964.12.03','YYYY.MM.DD') )); commit;

Um diese dauernden Schwierigkeiten zu umgehen, haben Sie auch die Mglichkeit, die Tabelle grundstzlich objektorientiert anzulegen (sog. Object Tables). In dem Fall besteht die Tabelle jedoch aus einem bzw. aus lauter Objekten, d.h. die Verwendung einzelner normaler Spalten ist hierbei nicht mehr mglich. Der Vorteil dabei ist allerdings, dass Oracle das Objekt anschlieend auflst und Sie die einzelnen Eigenschaften wie gewhnliche Spalten innerhalb von SQL-Ausdrcken verwenden knnen (vgl. Listing 2.18).
drop table menschen; / create table menschen of mensch tablespace usr; commit;
Listing 2.18: Anlegen einer objektorientierten Tabelle

Betrachten Sie die Tabellenbeschreibung wieder mit Hilfe des Befehls desc. Obwohl die Tabelle mit Hilfe eines Objekts definiert wurde, ist sie von einer klassischen Tabelle nicht mehr zu unterscheiden, d.h. alle Objekteigenschaften erscheinen wie ganz gewhnliche Tabellenspalten.
SQLWKS> desc menschen Column Name Null? ------------------------------ -------NAME VNAME STRASSE PLZ ORT GESCHL GEBDAT Type ---VARCHAR2(30) VARCHAR2(30) VARCHAR2(30) VARCHAR2(5) VARCHAR2(30) VARCHAR2(1) DATE

Damit stellt aber auch das Einfgen von Datenstze keine besondere Herausforderung mehr da, d.h. Sie knnen hierfr ganz gewhnliche insert-Anweisungen ohne irgendwelche Konstruktoren verwenden (CD: LISTING218A.SQL).
insert into menschen values ('Raymans', 'Heinz-Gerd', 'Harmoniestr. 2a','42110', 'Duisburg','M', to_date('1964.12.03','YYYY.MM.DD')); insert into menschen values ('Raymans','Irina',

136

Datenbankobjekte in einer Oracle-DB

'Harmoniestr. 2a', '42110', 'Duisburg', 'W', to_date('1965.12.27','YYYY.MM.DD')); insert into menschen values ('Zschoge','Helgo', 'Am kleinen Weg 11','10000','Berlin', 'M', to_date('1962.07.13','YYYY.MM.DD')); insert into menschen values ('Heger','Sascha', 'Hansaring 111a','50000','Kln','M', to_date('1969.05.12','YYYY.MM.DD')); commit;

hnlich wie bei den Packages unterteilt sich auch das Objekt in zwei Teile. Den erste Teil, in dem die Eigenschaften und sichtbaren Methoden verffentlicht wurden, haben Sie bereits fertiggestellt. Was noch fehlt ist die Programmierung der verffentlichten Methoden. Hierzu existiert bei den Objekten hnlich wie bei den Paketen der Type body, in dem die eigentliche Programmierung erfolgt (vgl. Listing 2.19).
create or replace type body mensch as member function g_alter return number is begin return floor(months_between(sysdate, gebdat) / 12) ; end; member function g_anschrift return varchar2 is anschrift varchar2(2000) := ' '; begin if geschl = 'M' then anschrift := 'Herrn' || chr(10) || chr(13); else anschrift := 'Frau' || chr(10) || chr(13); end if; anschrift := anschrift || vname || ' ' || name || chr(10) || chr(13); anschrift := anschrift || strasse || chr(10) || chr(13); anschrift := anschrift || plz || ' ' || ort; return anschrift; end; end; / show errors; commit;
Listing 2.19: Programmierung der zum Objekt gehrenden Methoden

Beschreibung der Objekte

137

Die erste Methode liefert das Alter, indem zunchst mit Hilfe der Standardfunktion month_between die Differenz zwischen dem Tages- und Geburtsdatums in Monaten berechnet wird. Diese Differenz teilen wir durch zwlf und schneiden von der Division alle Nachkommastellen mit Hilfe der floor-Funktion ab. Die zweite Member-Funktion sieht komplizierter aus, ist es aber nicht. Mit Hilfe des Operators || werden alle zur Anschrift gehrenden Einzelfelder aneinandergehngt (konkateniert), wobei an bestimmten Stellen auch die Steuerzeichen chr(10) und chr(13) eingestreut werden, die bei der spteren Ausgabe den gewnschten Zeilenwechsel veranlassen. Mit Hilfe der nun folgenden Abfrage, knnen Sie das Ergebnis Ihres Schaffens bewundern:
SQLWKS> select b.g_anschrift(), name, gebdat, b.g_alter() 2> from menschen b 3> where b.g_alter() > 18 B.G_ANSCHRIFT() NAME GEBDAT B.G_ALTER( ----------------------------- -------------------- -- ------ --------Herrn Heinz-Gerd Raymans Harmoniestr. 2a 42110 Duisburg Raymans 03-DEC-64 35 Frau Irina Raymans Harmoniestr. 2a 42110 Duisburg Raymans 27-DEC-65 34 Herrn Helgo Zschoge Am kleinen Weg 11 10000 Berlin Zschoge 13-JUL-62 38 Herrn Sascha Heger Hansaring 111a 50000 Kln Heger 12-MAY-69 31 4 rows selected.

2.2.7

Paketrumpf (Package bodies)

Diese Kategorie der Schema-Objekte beschreibt die in einem Package (Paket) enthaltenen Funktionen und Prozeduren. Mehr Informationen zu diesem Thema finden Sie im nchsten Abschnitt, der das Schema-Objekt Packages mitsamt den zugehrigen Package bodies beschreibt. Die Anweisung zum Anlegen eines Package bodies lautet create package body bzw. verwenden Sie create or replace package body, um das Schema-Objekt zu ersetzen. Mit Hilfe der Anweisung drop package body knnen Sie das zugehrige Objekt aus der Datenbank entfernen. Vergleicht man den Aufbau eines solchen Pakets, dann mit herkmmlichen Programmierkonstrukten, beispielsweise einem C-Programm, dann entspricht dieses Objekt dort am ehesten den blichen Modulen, in dem die einzelnen Prozeduren oder Funktionen programmiert werden.

138

Datenbankobjekte in einer Oracle-DB

2.2.8

Paket (Packages)

Nicht nur bei der (gelben) Post gibt es Pakete. In einer Oracle-Datenbank versteht man unter einem Package (Paket) die Zusammenfassung oder Verpackung verschiedener Prozeduren oder Funktionen zu einer Einheit. Genau wie im richtigen Leben besteht ein solches Paket meistens aus zwei Teilen, nmlich aus der Verpackung und (hoffentlich zu Weihnachten) auch aus (reichlich) Inhalt, wobei Letzteres in einer Oracle-Datenbank dem Package body gleichzuordnen ist. Aber manchmal erhlt man halt auch nur ein leeres Pckchen, was in unserer Datenbank einem Package ohne vorhandenem Package body entspricht. Zurck zum Ernst der Lage. Das Gesamtpaket besteht also (zumindest meistens) aus zwei Teilen, nmlich zum einen aus dem eigentlichen Package, das die Definition aller aufrufbaren Funktionen oder Prozeduren enthlt und damit die Hlle oder Verpackung darstellt und zum anderen aus dem Package body, in dem die einzelnen Funktionalitten ausprogrammiert werden, d.h. das Package body enthlt den Programmkode fr die im Package aufgezhlten Funktionen. Damit fungiert das Package auch als eine Art Schnittstelle zwischen dem Anwender oder anderen aufrufenden Programmen. Die im Paket enthaltenen Funktionen werden durch das Package sichtbar, wobei der zugehrige Programmcode im Package body verborgen bleibt (vgl. Abb. 2.5).

Anwendung Datenbank
-SQL*Plus -PL/SQL-Block -Anderes Package -Sonstige Anwendung

Package

Package Body

Abbildung 2.5: Schematischer Aufbau eines Packages

Wie schon im vorhergehenden Kapitel gesagt, kann man diese Konstruktion eines Packages seinem Package body durchaus mit herkmmlichen Programmiersprachen vergleichen. Dabei entspricht das Package body am ehesten den dort verwendeten Modulen, in den sich das eigentliche Programmcoding der einzelnen Funktionen und Prozeduren befindet. Daneben verwenden Sie in diesem Modulen blicherweise auch Prozeduren oder Funktionen, die in anderen Modulen realisiert wurden und vielleicht sogar erst zur Laufzeit Ihres Programms zur Verfgung stehen. Damit Sie Ihr Programm aber trotz des Fehlens dieser externen Funktionen umwandeln knnen, mssen Sie zumindest deren Namen und Parametrierung vorab definieren. Wenn Sie Erfahrungen mit den Programmiersprachen C oder Pascal haben, dann kennen Sie ja das ent-

Beschreibung der Objekte

139

sprechende Verfahren, solche Deklarations- bzw. Headerdateien via include oder uses einzubinden. Diese deklarative Eigenschaft weisen die Packages im brigen auch auf, denn sobald Sie das Package erstellt haben, knnen Sie die dort definierten Prozeduren oder Funktionen in anderen PL/SQL-Programmen ansprechen. Eine weitere Parallele ergibt sich auch im Bezug auf die Abstraktion der eigentlichen Programmierung. Wie Sie im weiteren Verlauf noch sehen werden, ist die eigentliche Programmierung im Package body fr andere Anwender nicht unbedingt sichtbar, d.h. eine bersicht des Inhalts ergibt sich alleine aus den im Package vorliegenden Definitionen. In anderen Programmierumgebungen erhalten Sie bestimmte Module oftmals nur in kompilierter Form, d.h. die eigentliche Kodierung der Funktionen ist auch hier nicht sichtbar. Die Verwendungen von Packages bietet einige Vorteile, vor allem dann, wenn man grere zusammenhngende Anwendungen entwickelt:

Selbst ein kleines Programm kann schnell zehn, zwanzig oder mehr einzelne Prozeduren beinhalten. Bentigt Ihre Anwendung nun auch noch eine Vielzahl solcher Programme, dann geht einem bei der Verwendung einzelner Prozeduren bzw. Funktionen neben der bersicht auch irgendwann einmal bei der Namensgebung die Phantasie aus. Aber selbst mit viel Phantasie haben Sie immer das Problem, dass die Namen der Prozeduren neu entwickelter Anwendungsteile noch nicht in der Datenbank vorhanden sein drfen. Durch die Zusammenfassung der einzelnen Prozeduren zu den Packages, treten die auf den ersten Blick in den Hintergrund, was einer besseren bersicht sehr zutrglich ist. Auerdem mssen die Namen der Prozeduren bzw. Funktionen nur innerhalb eines Paketes eindeutig sein; Ausnahmen besttigen auch hier mal wieder die Regel, da es die Mglichkeit gibt, Prozeduren mehrfach mit unterschiedlichen Parametern zu berladen. Nicht nur bei verteilten Entwicklungsaufgaben haben Packages den Vorteil, dass die enthaltenen Funktionen schon alleine mit deren Definition fr andere Anwendungen, quasi als Dummy, verfgbar sind. Die konkrete Ausprogrammierung im Package body kann erst zu einem spteren Zeitpunkt erfolgen. Wird eine in einem Package definierte Prozedur oder Funktion angesprochen, so wird in dem Fall zunchst das gesamte Paket geladen, wodurch auch alle anderen vorhandenen Funktionalitten verfgbar werden, was die Performance positiv beeinflussen kann. Werden in einem Package globale Variablen deklariert, dann sind die so lange gltig, bis sich der Benutzer wieder von der Datenbank abmeldet bzw. die aktuelle Sitzung (Session) beendet wird. Aufgrund dieses Verhaltens entsteht die Mglichkeit, quasi sitzungsglobale Variablen zu definieren. Ein Effekt, der in der Praxis durchaus genutzt wird und zu den schon angesprochenen leeren Paketen fhren kann, d.h. in dem Fall existiert zwecks Erhaltung globaler Variablen zwar ein Package aber kein zugehriges Package body.

: : :

140

Datenbankobjekte in einer Oracle-DB

Als letzten Aspekt mchte ich wieder etwas aus der Richtung Ordnung und bersicht anfhren, wenn auch aus einer anderen Blickrichtung. Wenn Sie Anwendungen in die Datenbank implementieren und hierzu entsprechende Prozeduren oder Funktionen entwerfen, dann mssen Sie in einem spteren Schritt blicherweise auch Ausfhrungsberechtigungen fr die Anwendung bzw. der zugehrigen Prozeduren vergeben. Sind die zu der Anwendung gehrigen Prozeduren in einem Paket vereint, dann reicht es aus, lediglich die Ausfhrung des Pakets zu erlauben.

Ein Paket wird mit Hilfe der Anweisung create or replace package und der Paketinhalt mit der Anweisung create or replace package body erstellt bzw. bearbeitet. Ersetzen Sie jeweils die Wrter create or replace durch das Wrtchen drop, um die Anweisung zum Lschen eines Paktes zu erhalten. Beachten Sie hierbei, dass Sie durch das Lschen eines Packages auch automatisch das zugehrige Package body lschen. Beispiele Es ist immer schwierig ein Beispiel zu finden, dass auf der einen Seite nicht zu lang und schwierig ist, aber auf der anderen Seite jedoch alle oder zumindest viele der mglichen Aspekte und Varianten bercksichtigt. In dem folgenden Beispiel, das zwar sicherlich wieder zur Klasse der EFOS-Funktionen (=Eine Funktion ohne Sinn) gehrt, ist das dennoch so wie ich glaube ganz gut gelungen. Konkret mchte ich die an der Erstellung unserer spiegeln-Funktion anknpfen, d.h. sollten Sie die Funktion zwischenzeitlich wieder gelscht haben, dann mssen Sie die zunchst einmal wieder anlegen. Anschlieend beginnen wir mit der Programmierung unseres Pakets tollhaus (vgl. Listing 2.20).
create or replace package tollhaus as call_count number; function spiegeln (in_c varchar2) return varchar2; pragma restrict_references (spiegeln, WNDS); end; / show errors; commit;
Listing 2.20: Definition des Packages tollhaus

Die Anlage des Pakets unterscheidet sich auf den ersten Blick zunchst einmal kaum von der von den Funktionen her bekannten Vorgehensweise. Lediglich das Wrtchen is habe ich zur Abwechslung einmal durch as ersetzt, was aber nicht unbedingt ntig gewesen wre. Aber auf den zweiten Blick treten mehr und mehr Unterschiede zum Vorschein. Zum Beispiel hat ein Paket nicht einmal einen einzigen Programmblock, d.h. die zugehrige begin-Anweisung fehlt und trotzdem wird eine Package-Definition mit end abgeschlossen.

Beschreibung der Objekte

141

Innerhalb der Paketdefinition wird als erstes die globale Variable call_count vom Datentyp number (Zahl) und anschlieend die Funktion spiegeln mit ihren Ein- und Ausgabeparametern definiert.
call_count number; function spiegeln (in_c varchar2) return varchar2;

Jede Variable, die einer create package-Anweisung folgt, ist global und fr die Lebensdauer der zugehrigen Session gltig. Jede definierte Funktion oder Prozedur kann vom Anwender oder einem anderen Programm aus gestartet (Zugriffsberechtigung vorausgesetzt) werden und muss im Rahmen der Erstellung des Package bodies angelegt bzw. programmiert werden. Nach der Funktion folgt noch eine weitere Anweisung pragma restrict_references, wobei es sich hierbei um eine sogenannte Compiler-Direktive handelt, mit der Sie fr die betreffende Funktion verschiedenste Einschrnkungen festlegen knnen.
pragma restrict_references (function_name, WNDS [, WNPS] [, RNDS] [, RNPS]);

Verwenden mssen Sie diese Compiler-Direktive zusammen mit dem betreffenden Funktions- oder Prozedurnamen und den gewnschten Einschrnkungen WNDS, WNPS, RNDS oder RNPS. Dabei ist nur die Einschrnkung WNDS zusammen mit dieser pragma-Anweisung zwingend, die anderen Einschrnkungen knnen wahlfrei verwendet werden. Diese Einschrnkungen, deren genaue Beschreibung Sie der Tabelle 2.2 entnehmen knnen, sind notwendig, wenn Sie die im Paket verfgbare Funktion innerhalb eines SQL-Ausdrucks verwenden mchten. Die Ausfhrung von Funktionen innerhalb von SQL-Ausdrcken ist an bestimmte Spielregeln gebunden, beispielsweise drfen innerhalb der Funktion keine Tabellendaten gendert werden. Bei gewhnlichen Funktionen, dass sind die auerhalb eines Pakets, achtet Oracle beim kompilieren der SQL-Anweisung selbst auf die Einhaltung dieser Regel. Ist die Funktion jedoch Bestandteil eines Paketes, dann ist der Code zunchst versteckt. Aus dem Grund mssen Sie die Funktion fr den Gebrauch innerhalb von SQL-Ausdrucken zertifizieren, was mit Hilfe der pragma-Anweisung passiert. In dem Fall achtet Oracle beim Anlegen der Funktion im Rahmen der Erstellung des Package bodies darauf, dass in den markierten Funktionen keine datenbankndernden Befehle verwendet werden.
Einschrnkung WNDS Beschreibung (writes no database state) Es knnen in der Datenbank keine Tabellennderungen durchgefhrt werden. Wichtig, damit die Funktion beispielsweise in der select-Klausel verwendet werden kann. (reads no database state) Innerhalb der Datenbank knnen keine Tabellen gelesen werden.

RNDS

142

Datenbankobjekte in einer Oracle-DB

Einschrnkung WNPS

Beschreibung (writes no package state) Die globalen Paketvariablen knnen nicht verndert werden. Das erlaubt die Verwendung der Funktion in der whereKlausel einer SQL-Abfrage. (reads no package state) Die globalen Paketvariablen knnen nicht gelesen werden.

RNPS

Tabelle 2.2: Optionen der restrict_references-Einstellung

Nachdem Sie nun das Package erstellt haben, mssen Sie im nchsten Schritt dessen Inhalt definieren. Bevor ich das konkrete Beispiel hier vorstelle und erklre, mchte ich zunchst einmal die grundstzliche Struktur (vgl. Listing 2.21) des Paketinhalts vorstellen.
create or replace package body tollhaus as 1) Deklarieren lokaler Funktionen und Prozeduren function kleingross(in_c varchar2) return varchar2; 2) Programmierung der globalen Funktion function spiegeln (in_c varchar2) return varchar2 is begin end; 3) Programmierung der lokalen Funktion function kleingross(in_c in varchar2) return varchar2 is out_c varchar2(254); begin end; 4) Programmieren des Initialisierungsteils begin -- Initialisieren globaler Variablen -- Spezielle Startroutinen end;
Listing 2.21: Schematischer Aufbau eines Package bodies

Das im Listing 2.21 gedruckte Schema eignet sich ganz gut, die prinzipielle Struktur eines Package bodies darzustellen und im folgenden Listing 2.22 finden Sie anschlieend das vollstndige Programm. Klar ist eigentlich, dass Package und Package body den gleichen Namen besitzen mssen. Den Rest finden Sie in der nun folgenden Aufzhlung:

Beschreibung der Objekte

143

1. Deklarieren Sie alle lokalen Funktionen. Genau genommen mssen Sie dies nur dann tun, wenn Sie die Funktion schon vor der eigentlichen Programmierung in einem anderen Programmteil aufrufen. In unserem Beispiel wre das genau dann der Fall, wenn Sie die Funktion kleingross erst an der mit 3. markierten Position erstellen, aber schon in dem spiegeln-programm verwenden mssen. Es schadet aber nicht, wenn Sie sich angewhnen, zunchst alle lokalen Funktionen und Prozeduren aufzuzhlen. 2. Programmieren Sie die globalen Funktionen und Prozeduren, also alle diejenigen, die im Package verffentlicht wurden. 3. Erstellen Sie die lokalen Funktionen und Prozeduren. Natrlich ist die bisher genannte Reihenfolge wie in den meisten Fllen nicht zwingend einzuhalten. Es doch zu tun, schadet aber in keinem Fall. 4. Programmieren Sie bei Bedarf einen speziellen Initialisierungsabschnitt. Hierzu finden Sie am Ende der create package body-Anweisung einen entsprechenden begin..end Block. Dieser Block wird direkt nach dem Laden des Pakets ausgefhrt und kann dazu genutzt werden, die globalen Variablen zu initialisieren oder spezielle Startroutinen aufzurufen.
create or replace package body tollhaus as function kleingross(in_c varchar2) return varchar2; function spiegeln (in_c varchar2) return varchar2 is begin call_count := call_count +1; if mod(call_count, 2) = 0 then return system.spiegeln(in_c); else return kleingross(in_c) || '>' || to_char(call_count) || '<'; end if; end; function kleingross(in_c in varchar2) return varchar2 is out_c varchar2(254); i number; begin for i in 1..length(in_c) loop if mod(i, 2) = 0 then out_c := out_c || lower(substr(in_c, i, 1)); else out_c := out_c || upper(substr(in_c, i, 1)); end if; end loop;

144

Datenbankobjekte in einer Oracle-DB

return out_c; end; begin call_count := 0; end; / show errors; commit;


Listing 2.22: Die vollstndige Tollhaus-Programmierung

Das eben gezeigte Listing entspricht genau der weiter oben beschrieben Struktur, weshalb ich im Wesentlichen auf die Beschreibung der einzelnen Funktionen konzentriere; nehmen wir das Programm im Folgenden also Stck fr Stck auseinander. Beginnen mchte ich mit dem kurzen Initialisierungsteil, in dem die globale Variable call_count auf Null gesetzt wird. Am Anfang der globalen Funktion spiegeln wird die globale Variable call_count bei jedem Aufruf um den Wert eins erhht. Innerhalb der nachfolgenden if-Abfrage wird nun mit Hilfe der mod-Funktion wird geprft, ob die globale Variable aktuell einen geraden oder ungeraden Wert enthlt.
if mod(call_count, 2) = 0 then

Diese mod-Funktion fhrt eine sogenannte Ganzzahldivision aus, d.h. nur bei geradezahligen Werten des Zhlers call_count liefert die oben abgebildete Berechnung den Wert Null. In dem Fall ruft unser Programm die schon erstellte spiegeln-Funktion auf und geben deren Rckgabe unverndert als Ergebnis aus. Damit klar ist, dass wir allerdings keineswegs unsere globale Paketfunktion noch einmal (rekursiv) aufrufen wollen, spezifizieren wir den Funktionsnamen vollstndig, indem wir dem Funktionsnamen den Namen des zugehrigen Schemas und einen Punkt als Trennzeichen voranstellen.
if mod(call_count, 2) = 0 then return system.spiegeln(in_c); else return kleingross(in_c) || '>' || to_char(call_count) || '<'; end if;

Bei ungeradezahligen Aufrufen verzweigen wir in die lokale kleingross-Funktion, dessen Rckgabewert wir zusammen mit dem Wert der Zhlervariablen ausgeben. Den konvertieren wir vorab mit Hilfe der Funktion to_char in eine Zeichenfolge, so dass wir die Funktionsrckgabe und den umgewandelten Zhler aneinanderhngen und zurckgeben knnen.
for i in 1..length(in_c) loop if mod(i, 2) = 0 then out_c := out_c || lower(substr(in_c, i, 1));

Beschreibung der Objekte

145

else out_c := out_c || upper(substr(in_c, i, 1)); end if; end loop;

Innerhalb unserer kleingross-Funktion durchlaufen wir den bergebenen String, so hnlich wie damals beim Spiegeln, wieder zeichenweise. Dabei kopieren wir Zeichen fr Zeichen in die Ausgabevariable out_c, wobei das jeweilige Zeichen in Abhngigkeit von der Stelle (gerade oder ungerade) mit Hilfe der Funktionen lower bzw. upper in Klein- bzw. Groschreibweise konvertiert wird. Die Verwendung bzw. der Aufruf unserer neuen Funktion erfolgt so hnlich wie in dem vorherigen Beispiel bei der Beschreibung der Funktionen. Einen kleinen Unterschied gibt es natrlich immer, und so mssen Sie bei Paketen der bentigten Funktion oder Prozedur den Namen des Packages gefolgt von einem Punkt als Trennzeichen voranstellen. Das gleich folgende Abfragebeispiel verwendet die neue spiegeln-Funktion wieder zusammen mit der v$option-View.
SQLWKS> select parameter, tollhaus.spiegeln(parameter) from v$option 2> PARAMETER TOLLHAUS.SPIEGELN(PARAMETER) ------------------------------------ ---------------------------------Partitioning PaRtItIoNiNg>1< Objects stcejbO Parallel Server PaRaLlEl sErVeR>3< Advanced replication noitacilper decnavdA Bit-mapped indexes BiT-MaPpEd iNdExEs>5< Connection multiplexing gnixelpitlum noitcennoC Connection pooling CoNnEcTiOn pOoLiNg>7< Database queuing gniueuq esabataD Incremental backup and recovery InCrEmEnTaL BaCkUp aNd rEcOvErY>9< Instead-of triggers sreggirt fo-daetsnI Parallel backup and recovery PaRaLlEl bAcKuP AnD ReCoVeRy>11< Parallel execution noitucexe lellaraP Parallel load PaRaLlEl lOaD>13< Point-in-time tablespace recovery yrevocer ecapselbat emit-ni-tnioP 14 rows selected.

Die Funktionsweise der globalen Zhlvariable call_count knnen Sie in dem Beispiel gut beobachten, indem Sie die abgebildete Abfrage einfach ein paar Mal hintereinander starten. Bauen Sie im nchsten Schritt vor der Abfrage eine connectAnweisung ein, um sich von der Datenbank ab- und sofort wieder anzumelden, und beobachten Sie anschlieend wieder die Werte der Zhlvariablen.
connect system/manager@db01; select parameter, tollhaus.spiegeln(parameter) from v$option

146

Datenbankobjekte in einer Oracle-DB

Wie nicht anders zu erwarten wird hierdurch die Zhlvariable wieder auf Null gesetzt, da diese wegen der neuen Session beim Starten des Packages erneut initialisiert wird. Natrlich besteht auch die Mglichkeit, die globale Zhlvariable von auen gezielt zu beeinflussen. Wie das geht, das zeigt Ihnen das nchste Beispiel:
Begin tollhaus.call_count := 111; end; / select parameter, tollhaus.spiegeln(parameter) from v$option

So, damit wre der erste Teil meines Package-Beispiels beendet und Sie mssen zugeben, auch wenn es inhaltlich nicht besonderes schwergewichtig war, kam dennoch alles Wesentliche darin vor. Sie haben ein Paket mit einer verffentlichten und einer privaten Funktion erstellt, eine globale Variable benutzt, gesehen wie man von auen die Paketfunktion aufruft und die globale Variable verwendet. Varianten Wie Sie sich vielleicht erinnern, hatte ich am Anfang des Kapitels gesagt, dass es im Ausnahmefall mglich ist, Funktions- bzw. Prozedurnamen in einem Paket mehrfach zu verwenden. Das ist genau dann sinnvoll, wenn Sie die zugehrige Funktion mit verschiedenen Parametern verwenden wollen, wobei man in dem Fall vom berladen der Funktion bzw. Prozedur spricht. Wenn wir diese Anforderung auf unser Beispiel bertragen, dann lge eine passende Aufgabenstellung darin, die spiegeln-funktion nicht nur fr eine Zeichenkette, sondern vielleicht auch mit einem Datum aufrufen zu knnen. Im nchsten Listing 2.23 knnen Sie hierzu zunchst einmal die Deklaration der Funktionen im Package betrachten.
create or replace package tollhaus as call_count number; function spiegeln (in_c varchar2) return varchar2; pragma restrict_references (spiegeln, WNDS); function spiegeln (in_c date) return varchar2; pragma restrict_references (spiegeln, WNDS); function spiegeln (in_c varchar2, i integer) return varchar2; pragma restrict_references (spiegeln, WNDS); end; / show errors; commit;
Listing 2.23: Mehrfachdeklaration der spiegeln-Funktion

Beschreibung der Objekte

147

Wie Sie dem Listing entnehmen knnen, ist die notwendige Verfahrensweise eigentlich gar nicht weiter schwierig. Die entsprechende Funktion wird so oft mit den jeweiligen Parametern aufgefhrt, bis alle bentigen Parametervarianten aufgezhlt sind. Hierbei mssen Sie lediglich darauf achten, dass Sie eventuell notwendige Compileroptionen ebenfalls entsprechend oft und jetzt am besten direkt hinter der Funktionsdeklaration schreiben. Naheliegenderweise mssen Sie die eigentliche Funktion im Package body jetzt auch entsprechend hufig kodieren (vgl. Listing 2.24). Auch wenn es in meinem Beispiel vielleicht den Eindruck macht, so mssen Sie hierbei die im Package verwendete Reihenfolge nicht einhalten. Aber da ich ein so ordnungsliebender Mensch bin, jetzt werden einige Leute herzhaft lachen, habe ich im folgenden Beispiel die gleiche Reihenfolge gewhlt.
create or replace package body tollhaus as function kleingross(in_c varchar2) return varchar2; function spiegeln (in_c varchar2) return varchar2 is begin call_count := call_count +1; if mod(call_count, 2) = 0 then return system.spiegeln(in_c); else return kleingross(in_c) || '>' || to_char(call_count) || '<'; end if; end; function spiegeln (in_c date) return varchar2 is begin return system.spiegeln(to_char(in_c,'YYYY.MM.DD')); end; function spiegeln (in_c varchar2, i integer) return varchar2 is begin return in_c; end; function kleingross(in_c in varchar2) return varchar2 is out_c varchar2(254); i number; begin for i in 1..length(in_c) loop if mod(i, 2) = 0 then out_c := out_c || lower(substr(in_c, i, 1));

148

Datenbankobjekte in einer Oracle-DB

else out_c := out_c || upper(substr(in_c, i, 1)); end if; end loop; return out_c; end; begin call_count := 0; end; / show errors; commit;
Listing 2.24: Variante des Tollhauses mit berladener spiegeln-Funktion

Lediglich der fettgedruckte Abschnitt im Listing ist neu und was da im Einzelnen passiert, ist auch nicht besonders aufregend. Im Fall eines bergebenen Datums wird das innerhalb der zweiten Variante mit Hilfe der Funktion to_char in eine Zeichenkette umgewandelt, so dass wir anschlieend wieder unsere altbekannte Funktion system.spiegeln benutzen knnen. Die dritte Variante wird verwendet, wenn wir die Paketfunktion mit zwei Parametern (Zeichenkette und Zahl) aufrufen. In dem Fall geben wir den bergebenen Wert unverndert zurck. Auf zur Tat und damit zum Test unserer neuen Funktionen. Mit Hilfe der im Folgenden gedruckten Abfrage knnen Sie die verschiedenen Varianten ausprobieren und damit zum letzten Mal einen berblick ber die in Ihrer Datenbank installierten Optionen erhalten, wobei Sie im Folgenden nur einen aufbereiteten Auszug der zugehrigen Abfrage sehen.
SQLWKS> select 2> tollhaus.spiegeln(parameter,1), 3> tollhaus.spiegeln(parameter), 4> tollhaus.spiegeln(sysdate) 5> from v$option 6> SPIEGELN(PARAMETER,1) SPIEGELN(PARAMETER) SPIEGELN(SYSDATE) -------------------------------- -------------------------------------Partitioning PaRtItIoNiNg>15< 80.80.0002 Objects stcejbO 80.80.0002 Parallel Server PaRaLlEl sErVeR>17< 80.80.0002 Advanced replication noitacilper decnavdA 80.80.0002 Bit-mapped indexes BiT-MaPpEd iNdExEs>19< 80.80.0002 Connection multiplexing gnixelpitlum noitcennoC 80.80.0002 Connection pooling CoNnEcTiOn pOoLiNg>21< 80.80.0002 Database queuing gniueuq esabataD 80.80.0002 ... 14 rows selected.

Beschreibung der Objekte

149

2.2.9

Prozedur (Procedures)

An dieser Stelle knnte ich jetzt die im Kapitel Functions geschriebenen Abstze kopieren, und danach das Wrtchen Function per Suchen und Ersetzen mit Procedure ersetzen, um eine geeignete Einleitung fr die folgenden Abschnitte zu erhalten. Aber der Platz in diesem Buch ist kostbar und ich will Sie auch nicht unntig langweilen. In der Tat sind Prozeduren und Funktionen nicht nur in Oracle, sondern eigentlich in jeder Programmiersprache nahe Verwandte. In beiden Fllen handelt es sich um mehr oder weniger komplexe Programme, die zusammen mit einem oder mehreren Parametern aufgerufen werden. Was sich natrlich unterscheidet, ist die genaue Verwendung dieser beiden Konstrukte. Eine Funktion knnen Sie wegen der besonderen Verwendungsform, Parameter rein und Ergebnis ber den Funktionsnamen raus, direkt innerhalb von Ausdrcken, select- oder where-Anweisungen benutzen. Dahingegen bedrfen die Prozeduren eines speziellen Aufrufs und knnen daher nur im Rahmen einer einzelnen SQL-Anweisung oder innerhalb eines PL/SQL-Skripts oder Programms verwendet werden. Die Anlage einer Prozedur erfolgt in Analogie zu den Funktionen mit Hilfe der Anweisung create procedure und eine notwendige nderung leiten Sie wieder mit Hilfe des Befehls create or replace procedure ein. Eine nicht mehr bentigte Prozedur knnen Sie mit der Anweisung drop procedure fr immer verschwinden lassen. Beispiele Oftmals werden Prozeduren erstellt bzw. verwendet, um zusammenhngende SQLAnweisungen quasi als einen Block auszufhren. Soll beispielsweise aus einer Gehaltsdatendatenbank ein Mitarbeiter gelscht werden, dann mssen in der Regel neben dem Stammdatensatz auch eine Reihe weitere Datenstze aus anderen Tabellen (z.B. Lohnkonten, Gehaltshistorien usw.) gelscht werden, d.h. fr jede betreffende Tabelle msste eine entsprechende delete-Anweisung abgesetzt werden, die alle zum Mitarbeiter gehrenden Stze lscht (vgl. Listing 2.25).
create or replace procedure del_mitarbeiter (in_persnr in varchar2) is begin delete mitarbeiter where persnr = in_persnr; commit; end; / show errors; commit;
Listing 2.25: Prozedur zum Lschen zusammengehrenden Tabellen

Natrlich ist dieses Beispiel sehr vereinfachend. In der Praxis wrden innerhalb der Prozedur vielleicht sogar hunderter hnlicher Lschanweisungen fr andere Tabellen abgesetzt, um den Mitarbeiter nicht nur aus der einen, sondern eben aus allen ntigen Tabellen der Datenbank zu lschen. Noch besser wre natrlich eine Prozedur, die automatisch innerhalb einer Schleife alle Tabellen findet, aus der Daten

150

Datenbankobjekte in einer Oracle-DB

fr diesen Mitarbeiter gelscht werden mssen. Sie werden spter im Kapitel PL/ SQL-Programmierung Anregungen fr eine solche Prozedur erhalten, denn dort werden wir etwas hnliches zum Reorganisieren von Indexen erstellen. Doch nun zurck zu unserem kleinen und harmlosen Beispiel, in dem Sie die Prozedur del_mitarbeiter erstellen, wobei die Verfahrensweise mit der einer Funktionserstellung nahezu identisch ist. Nach Nennung des Prozedurnamens und Aufzhlung der Parameter erfolgt wieder die Kodierung des eigentlichen Prozedurprogramms zwischen dem mit begin und end festgelegten Block. hnlich wie bei den Funktionen gilt auch hier, dass Sie hinter dem Schlsselwort is bzw. as die Variablen fr den ersten Programmblock ohne explizite declare-Anweisung definiert werden knnen und bezglich der Parameterlisten mchte ich hier nur auf die Tabelle 2.1 verweisen.
create or replace procedure del_mitarbeiter (in_persnr in varchar2) is i number; begin delete mitarbeiter where persnr = in_persnr; commit end; / show errors; commit;
Listing 2.26: Prozedurrumpf mit eigenen lokalen Variablen

Wenn Sie nun eine dieser beiden Prozeduren ausprobieren mchten, dann knnen Sie dies mit Hilfe von SQL*Plus oder dem SQL-Worksheet und der execute-Anweisung tun. Diese Anweisung startet eine Prozedur als einzelne SQL-Anweisung, die natrlich auch zusammen mit einer Reiher anderer Anweisungen verwendet werden kann:
select count(*) from mitarbeiter; execute del_mitarbeiter('4711'); select count(*) from mitarbeiter;

Zusammen mit einem SQL-Skript oder innerhalb einer anderen Prozedur oder Funktion entfllt allerdings die execute-Anweisung fr den Aufruf der Prozedur, d.h. die Prozedur wird einfach durch Verwendung ihres Namens gestartet:
select count(*) from mitarbeiter; / begin del_mitarbeiter('4712'); end; / select count(*) from mitarbeiter;

Beschreibung der Objekte

151

Im Rahmen des Kapitels PL/SQL-Programmierung werden Sie komplexere Beispiele zur Verwendung von Prozeduren kennen lernen. Ein weiteres oftmals genutztes Einsatzgebiet ist nmlich auch die Bndelung von notwendigen Wartungsarbeiten, beispielsweise dem reorganisieren von Indices, wofr wir, wie schon erwhnt, in dem genannten Kapitel ein Muster erstellen werden.

2.2.10 Warteschlangentabelle (Queue Tables)


Es gibt Dinge, da steht eigentlich weniger die Technik in den Vordergrund als das dahinter liegende Konzept bzw. die damit verbundenen Mglichkeiten. Das gilt meiner Meinung nach auch fr die hier vorgestellte Gruppe der Schema-Objekte. Falls Sie die brigens in Ihrem Schema-Manager nicht sehen sollten, dann liegt das wieder an den verfgbaren oder installierten Optionen Ihres Oracle-Servers. Konkret bentigen Sie wenigstens die Enterprise Edition, um das Schema-Objekt Queue Tables anlegen zu knnen, wobei die vollstndige Palette der Funktionen nur zusammen mit den Objekten zur Verfgung steht. Im Prinzip stellt Oracle mit diesem Schema ein Werkzeug zur Verfgung, um die Kommunikation zwischen verschiedenen Programmen bzw. Prozessen zu gestalten. Oftmals kommunizieren verschiedene Programme synchron miteinander, d.h. ein Programm ruft den Dienst eines anderen Unterprogramms auf und wartet anschlieend so lange, bis dieses Unterprogramm terminiert (fertig wird). Eine solche Verfahrensweise ist immer dann sinnvoll, wenn unter normalen Umstnden davon ausgegangen werden kann, dass der aufgerufene Programmteil den gewnschten Dienst in einer akzeptablen Zeit erledigen kann. Was ist aber zu tun, wenn genau diese Voraussetzung nicht erfllt ist bzw. garantiert werden kann? Manchmal kann es technische Grnde dafr geben, dass die zeitnahe Ausfhrung des aufgerufenen Programms nicht mglich ist. Das ist zum Beispiel dann der Fall, wenn das zugehrige Programm oder eine von dem Programm bentigte Datenbank wegen Wartungsarbeiten nicht verfgbar ist, oder der angestoene Prozess dauert wirklich sehr lange, beispielsweise weil Sie einen komplexen Suchvorgang in einer riesigen Datenbank gestartet haben. Nach meiner Erfahrung sind es jedoch oftmals vor allem organisatorische bzw. fachliche Grnde, die gegen eine synchrone Verarbeitung sprechen. Stellen Sie sich vor, Sie ordern online ein Aktienpaket mit entsprechender Limitvorgabe. Mit dem Absenden des Auftrags kann aber berhaupt noch nicht vorhergesagt werden, wann bzw. ob diese Transaktion ausgefhrt wird, denn auf der Gegenseite mssen verschiedene Voraussetzungen erfllt sein, damit das Geschft zustande kommt. Zum einen muss das vorgegebene Limit ziehen und zum anderen muss es jemanden geben, der eine entsprechende Aktienstckzahl zum Verkauf aufgegeben hat. Weitere Beispiele fr eine derartige asynchrone Verarbeitung ergeben sich immer dann, wenn man Arbeitsprozesse nachbildet, vor allem dann, wenn an dem gesamten Ablauf mehrere verschiedene Personen beteiligt sind (vgl. Abb. 2.6).

152

Datenbankobjekte in einer Oracle-DB

Kunde

eingeben

prfen

freigeben

abwickeln

Nachrichten

Hintergrundprozesse
Abbildung 2.6: Schema eines Arbeitsprozesses

In dem Beispiel soll die vereinfachte Verarbeitung eines Kreditantrags dargestellt werden, die damit startet, dass der Kunde den Antrag selbstndig, beispielsweise im Internet, eingibt. Anschlieend wird der vom Sachbearbeiter A geprft, was gegebenenfalls die Freigabe des Antrags durch den Sachbearbeiter B zur Folge hat, worauf wiederum der Sachbearbeiter A die eigentliche Abwicklung durchfhrt, beispielsweise den Vertrag erstellt oder das Geld auszahlt. Damit diese einzelnen Arbeitsschritte wirklich wie an der Perlenkette hngend ablaufen, mssen sie miteinander kommunizieren. Diese Kommunikation muss aber asynchron erfolgen, denn der Sachbearbeiter A kann nach der Prfung eines Vertrages nicht so lange in Wartestellung verharren, bis sein Vorgesetzter endlich die Freigabe erteilt hat. Die Kommunikation der einzelnen Arbeitsschritte erfolgt mit Hilfe von Nachrichten, beispielsweise in der Form

: : :

Neuer Antrag ist eingetroffen, Antrag wurde geprft, bitte freigeben, Antrag freigegeben, bitte abwickeln.

Damit alle Beteiligen die fr sie interessanten Nachrichten lesen bzw. bearbeiten knnen, erfolgt eine gemeinsame Speicherung in einem Pool, der sogenannten Message-Queue. Das alleinige Vorhandensein einer solchen Queue reicht fr die Bearbeitung der dort gespeicherten Nachrichten allerdings meistens nicht aus, sondern Sie bentigen blicherweise auch noch eine Reihe von Helfern in Form von verschiedenen Hintergrundprozessen. Die berwachen beispielsweise den Verlauf der Nachrichtenkette, schlagen Alarm, wenn bestimmte Ereignisse nach Ablauf einer bestimmten Frist nicht bearbeitet wurden, lschen unvollstndige oder alte

Beschreibung der Objekte

153

Nachrichten aus dem Pool heraus oder stoen andere Batchprozesse aufgrund erledigter Nachrichten an. Wie Sie an dem Beispiel erkennen knnen geht es also nicht nur darum, in der Datenbank eine simple Tabelle anzulegen, in der Nachrichten in Form gewhnlicher Datenstze gespeichert werden, sondern zu einer solchen Verarbeitung gehrt auch die Mglichkeit, entsprechende Hintergrundprozesse zu definieren. brigens gibt es auch synchrone Verarbeitungsformen, in der die Kommunikation trotzdem ber Nachrichten und entsprechender Queues erfolgt. In dem Fall wartet der einstellende Prozess so lange auf die Quittung oder Erledigung, bis diese beispielsweise durch einen Hintergrundprozess eintrifft. Das Betriebssystem Windows arbeitet zum Beispiel oftmals nach diesem Prinzip. Die Kommunikation zwischen den eigentlichen Anwendungen und dem Windows-Kern basiert auf Nachrichten und trotzdem warten viele Funktionen nach dem Einstellen einer Nachricht so lange, bis deren Verarbeitung quittiert wurde. Was Sie nun im Schema-Manager unter der Rubrik Queue Tables sehen, ist die Mglichkeit, solche Nachrichtenpools zu erstellen. Dabei handelt es sich zum einen um ganz gewhnliche Tabellen aber zum anderen mit einem speziellen Aufbau bzw. mit speziellen Feldern, denn Oracle bietet neben diesen Tabellen auch in der Datenbank implementierte Funktionalitten, um die beschriebenen Hintergrundprozesse zu realisieren. Die Anlage bzw. Verwaltung dieser speziellen Tabellen erfolgt mit Hilfe des Paktes dbms_aqadm. Im folgenden Listing sehen Sie ein Beispiel fr dessen Verwendung, die zugehrigen Definitionen erfolgten mit Hilfe des Schema-Managers, wobei Sie die wichtigen Einstellungen in Abbildung 2.7 finden. Danach erhalten Sie mit dem Listing 2.27 einen berblick ber das Aussehen der erstellten Nachrichtentabelle und zum Schluss (Listing 2.28) sehen Sie, wie Sie die Nachrichtentabelle mit Hilfe des dbms_aqadm-Pakets wieder lschen knnen.
BEGIN dbms_aqadm.create_queue_table(queue_table=> 'SYSTEM.nachrichtenpool', queue_payload_type=>'RAW', sort_list=>'ENQ_TIME', comment=>'Beispiel fr die Anlage des Pools', multiple_consumers=>FALSE, message_grouping=>DBMS_AQADM.NONE, storage_clause=>' PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 STORAGE ( INITIAL 12K NEXT 12K MINEXTENTS 1 MAXEXTENTS 249 PCTINCREASE 0) TABLESPACE "SYSTEM" '); COMMIT; END;
Listing 2.27: Beispiel fr das Anlegen einer Nachrichten-Queue

154

Datenbankobjekte in einer Oracle-DB

Hinweis: Das abgebildete Beispiel verwendet bei der Spezifizierung der Prozedurparameter die namensbezogene bergabe. Bisher haben wir in allen unseren Beispielen die sogenannte positionsbezogene Parameterbergabe verwendet, d.h. in dem Fall muss die verwendete Reihenfolge der Notierung der Variablen im Prozedurkopf entsprechen. Bei der namensbezogenen bergabe mssen Sie jedem bergebenen Wert den zugehrigen Parameternamen zusammen mit dem Operator => voranstellen.

Abbildung 2.7: Definition der Queue im Schema-Manager

SQLWKS> desc nachrichtenpool Column Name Null? ------------------------------ -------Q_NAME MSGID CORRID PRIORITY STATE DELAY EXPIRATION TIME_MANAGER_INFO LOCAL_ORDER_NO CHAIN_NO CSCN DSCN

Type ---VARCHAR2(30) RAW(16) VARCHAR2(128) NUMBER NUMBER DATE NUMBER DATE NUMBER NUMBER NUMBER NUMBER

Beschreibung der Objekte

155

ENQ_TIME ENQ_UID ENQ_TID DEQ_TIME DEQ_UID DEQ_TID RETRY_COUNT EXCEPTION_QSCHEMA EXCEPTION_QUEUE STEP_NO RECIPIENT_KEY DEQUEUE_MSGID USER_DATA

DATE NUMBER VARCHAR2(30) DATE NUMBER VARCHAR2(30) NUMBER VARCHAR2(30) VARCHAR2(30) NUMBER NUMBER RAW(16) BLOB(4000)

Listing 2.28: Aufbau des angelegten Nachrichtenpools

Wie Sie der Abbildung 2.7 bzw. auch der bersicht (Listing 2.28) entnehmen knnen, dienen solche Nachrichten nicht nur unbedingt zum Weiterleiten der Ereignisse, sondern enthalten unter Umstnden auch die zum Bearbeiten bentigten Daten.
BEGIN dbms_aqadm.drop_queue_table(queue_table=> 'SYSTEM.NACHRICHTENPOOL', force=> TRUE); COMMIT; END; / EXIT;
Listing 2.29: Lschen des Nachrichtenpools

Weitergehende Informationen zu diesem Thema finden Sie mal wieder in dem Buch Oracle8 Concepts im Kapitel Advanced Queuing. Da die Erstellung und Verwendung solcher Nachrichtentabellen natrlich auch eine Herausforderung an die gesamte Anwendungsentwicklung stellt, finden Sie auch dort (Oracle8 Application Developers Guide) ebenfalls im Kapitel Advanced Queuing viele Hinweise und Beispiele. Resume Was ist an dem eben beschriebenen Verfahren und Mglichkeiten eigentlich so neu und aufregend? Nun, zunchst einmal gar nichts. Die eben beschriebenen Verfahrensweisen wurden bei Bedarf eigentlich schon immer verwendet und stellen keine Neuerfindung von Oracle dar. Allerdings mussten die bentigten Pooltabellen selbst definiert und vor allem die bentigten Hintergrundprozesse selbst programmiert werden. Meistens erfolgte dies je nach Betriebsplattform mit entsprechenden C, Cobol oder SQR-Programmen, die auf einem zentralen Server mit Hilfe von Betriebssystemfunktionen getriggert wurden.

156

Datenbankobjekte in einer Oracle-DB

Manchmal liefern sogar Standardprogramme (z.B. PeopleSoft oder SAP) selbst geeignete Werkzeuge, um solche Hintergrundjobs zu planen und zu berwachen, wobei es sich auch hierbei um separate Anwendungsprogramme handelt, die auerhalb der Datenbank gestartet und administriert werden. Um auf die Eingangsfrage zurckzukommen: Neu ist im Unterschied zu den eben beschriebenen Verfahrensweisen, dass Sie jetzt die Mglichkeit haben, die gesamte Steuerung, Administration und Programmierung des Nachrichtensystems innerhalb der Datenbank durchzufhren. Dabei sind neben den Tabellen nicht nur die Programme der Hintergrundprozesse Bestandteil der Datenbank, sondern sie beinhaltet auch alle Funktionalitten zur Planung, Steuerung und berwachung dieser Prozesse.

2.2.11 Abgleichengruppe (Refresh groups)


Eine Refresh group wird im Zusammenhang mit den sogenannten Snapshots verwendet und von mir auch erst weiter unten in dem zugehrigen Abschnitt ausfhrlicher behandelt. Vorwegnehmend mchte ich an dieser Stelle nur soviel sagen: Die Refresh groups helfen, die Aktualisierung der Schnappschusstabellen (Snapshots) zu organisieren, indem alle zu einer solchen Aktualisierungsgruppe gehrenden Schnappschsse gleichzeitig bzw. zusammenhngend aufgefrischt werden. Auerdem bietet Ihnen dieses Objekt noch die zustzliche Option, die Schnappschussaktualisierungen in regelmigen Abstnden automatisch durchzufhren. Zum Anlegen bzw. Verwalten der Refresh groups finden Sie diesmal keine der bisher blichen SQL-Befehle, sondern das erfolgt mit Hilfe des Standard-Pakets dbms_refresh, genauer genommen sys.dbms_refresh, da der Benutzer sys Eigentmer des Pakets ist. Wenn Sie eine solche Gruppe fr die automatische Aktualisierung konfigurieren, dann mssen Sie auch zustzlich am Datenbankserver noch einige Einstellungen vornehmen. Die automatische Aktualisierung erfolgt mit Hilfe sogenannter SNP Hintergrundprozesse, die mit Hilfe der Konfigurationsdatei der Datenbankinstanz eingeschaltet werden. Mehr Informationen hierzu finden Sie in der Dokumentation im Oracle8 Administrators Guide und dort im Kapitel Managing Job Queues.

2.2.12 Sequenz (Sequences)


Mit diesem Schema-Objekt erhalten Sie ein Hilfsmittel, um automatisch eindeutige Integerzahlen zu erzeugen. Ein solcher Zahlengenerator ist oftmals recht praktisch, beispielsweise wenn Sie in einer Tabelle einen Primrschlssel anlegen wollen, sich hierfr aber kein eigenes Feld bzw. keine Feldkombination anbietet. In dem Fall knnen Sie von dem hier beschriebenen Zahlengenerator fr jeden Datensatz eine eindeutige fortlaufende Nummer abfordern, so dass Sie auf einfache Weise Ihren Hilfs-Primrschlssel erhalten. Die Anlage solcher Sequences erfolgt mit Hilfe der Anweisung create sequence. Mit dem Befehl alter sequence knnen Sie die Einstellungen des Zahlengenerators ndern und wenn Sie ihn nicht mehr brauchen, dann lschen Sie Ihn mit der Anweisung drop sequence aus der Datenbank.

Beschreibung der Objekte

157

Beispiele In einer Tabelle soll zur spteren Identifizierung eines jeden Datensatzes ein automatischer Zhler eingebaut werden. Zu dem Zweck legen wir in der Datenbank als ersten den Zhler unter dem Namen meinzaehler (vgl. Listing 2.30) an.
create sequence meinzaehler increment by 1 start with 1 maxvalue 5 minvalue 1 cycle cache 4 noorder; commit
Listing 2.30: Anlage des Zahlengenerators meinzaehler

Wie Sie sehen, besitzt die Anweisung eine ganze Reihe von Parametern, die ich in der folgenden Tabelle 2.3 kurz beschreiben mchte.
Parameter increment by Beschreibung Legt die Schrittfolge des Zahlengenerators und damit die nchste gelieferte Zahl fest. Mglich sind positive, aber auch negative Zahlen, d.h. der Zahlengenerator kann auch rckwrts zhlen. Anfangswert fr die Zahlenfolge. Maximal mglicher Wert bzw. verwenden Sie die Option nomaxvalue, wenn der Zhler bis zum technischen Limit (28-stellige Zahlen) weiterlaufen soll. Kleinster zu liefender Wert. Wenn Sie stattdessen die Option nominvalue verwenden, dann betrgt die kleinste lieferbare Zahl 1 * 1026. In dem Fall (cycle) luft der Zahlengenerator wie eine Uhr immer im Kreis, d.h. nach Lieferung der maximal eingestellten Zahl geht es wieder von vorne los. Die Option nocycle entspricht dem Standardwert. Mit dem cache-Parameter knnen Sie die Anzahl der Zahlen festlegen, die vorausberechnet und im Speicher vorgehalten werden. Eine ausgewogene Einstellung dieses Wertes kann die Geschwindigkeit des Zhlers erhhen. Die Standardoption noorder legt fest, dass die Reihenfolge der Nummernvergabe nicht unbedingt der ihrer Anforderung entsprechen muss. Fordern zwei Transaktionen eine neue Nummer an und soll die erste Transaktion garantiert auch die nchsthhere Nummer erhalten, dann mssen Sie die Option order verwenden.

start with maxvalue / nomaxvalue

minvalue / nominvalue

cycle / nocycle

cache / nocache

noorder / order

Tabelle 2.3: Einstellmglichkeiten des Zahlengenerators

158

Datenbankobjekte in einer Oracle-DB

Ist der Zahlengenerator erst einmal definiert, dann knnen Sie von ihm mit Hilfe des Befehls nextval den nchsten Wert anfordern bzw. mit der Anweisung currval den aktuellen Wert abfragen. Viel mehr ist bei der Verwendung eines solchen Zhlers eigentlich auch nicht zu beachten. Allerdings sollte man bercksichtigen, dass ein solcher Zahlengenerator grundstzlich unabhngig von irgendwelchen Tabellen konzipiert ist. Konkret kann ein solcher Zhler sowohl parallel fr verschiedene Tabellen oder auch vielleicht zum Zhlen bestimmter Programmaufrufe verwendet werden. Mit Hilfe des nchsten Listings knnen Sie eine kleine Tabelle erstellen, mit der Sie die Verwendung des Zahlengenerators demonstrieren knnen.
drop table bekannte; / create table bekannte ( lfdnr number, name varchar2(50)) tablespace urs; commit;

Anschlieend werden in diese Tabelle beliebige Daten eingefgt, wobei die laufende Nummer mit Hilfe des Zahlenlieferanten meinzaehler erzeugt wird.
insert into insert into insert into insert into insert into insert into commit; bekannte bekannte bekannte bekannte bekannte bekannte values(meinzaehler.nextval, values(meinzaehler.nextval, values(meinzaehler.nextval, values(meinzaehler.nextval, values(meinzaehler.nextval, values(meinzaehler.nextval, 'Heidi'); 'Bibi'); 'Ruber Hotzenplotz'); 'Tina und Sabrina'); 'Rotkppchen'); 'Aschenputtel');

Fhren Sie nun eine Abfrage auf diese Tabelle aus, um die Vergabe der laufenden Nummer zu kontrollieren. Aufgrund des verwendeten Parameters cycle und des eingestellten Maximalwertes von fnf haben wir bei den sechs eingefgten Datenstzen halt schon einen Rundlauf hinter uns gebracht.
SQLWKS> select * from bekannte 2> LFDNR NAME ---------- --------------------------------1 Heidi 2 Bibi 3 Ruber Hotzenplotz 4 Tina und Sabrina 5 Rotkppchen 1 Aschenputtel 6 rows selected.

Mit Hilfe der Anweisung alter sequence knnen Sie fast alle oben beschriebenen Einstellungen verndern. Ausgenommen hiervon ist lediglich der Anfangswert des Zahlengenerators, den Sie bei der Anlage mittels start with festgelegt haben. Im

Beschreibung der Objekte

159

nchsten Beispiel werden wir an unserem Generator ein paar Einstellungen verndern, beispielsweise den Maximalwert auf fnfzig Zahlen hochsetzen, den Rundlauf ausschalten und die Vorausberechnung auf zwanzig Werte einstellen.
alter sequence meinzaehler maxvalue 50 nocycle cache 20; commit;

Mit Hilfe des nchsten Skripts (vgl. Listing 2.20) probieren wir den Zhler auch gleich wieder aus. Zunchst lscht es die Tabelle noch einmal und fgt die gleichen Datenstze anschlieend noch einmal ein. Allerdings werden zwischendurch auch im Rahmen einer gewhnlichen Auswahlabfrage Werte vom Zahlengenerator abgefragt. Hierdurch soll dieses Beispiel demonstrieren was passiert, wenn ein Zahlengenerator fr verschiedene Zwecke oder fr unterschiedliche Tabellen verwendet wird. Das Ergebnis dieser Aktionen knnen Sie mit Hilfe der anschlieend abgebildeten Abfrage (siehe Listing 2.31) betrachten.
truncate table bekannte; insert into bekannte values(meinzaehler.nextval, insert into bekannte values(meinzaehler.nextval, select meinzaehler.nextval from v$database; select meinzaehler.nextval from v$database; select meinzaehler.nextval from v$database; select meinzaehler.nextval from v$database; insert into bekannte values(meinzaehler.nextval, insert into bekannte values(meinzaehler.nextval, insert into bekannte values(meinzaehler.nextval, select meinzaehler.nextval from v$database; insert into bekannte values(meinzaehler.nextval, commit; 'Heidi'); 'Bibi');

'Ruber Hotzenplotz'); 'Tina und Sabrina'); 'Rotkppchen'); 'Aschenputtel');

Listing 2.31: Erneutes Einfgen der Daten mit Zweckentfremdung des Zhlers

SQLWKS> select * from bekannte 2> LFDNR ---------- ------------------------3 Heidi 4 Bibi 9 Ruber Hotzenplotz 10 Tina und Sabrina 11 Rotkppchen 13 Aschenputtel 6 rows selected.
Listing 2.32: Kontrolle der vergebenen Nummern

160

Datenbankobjekte in einer Oracle-DB

Wie nicht anders zu erwarten war, entstehen bei einer derartigen Zweckentfremdung des Zahlengenerators Lcken in der Nummerierung, d.h. die durch dieses Objekt gelieferte Zahlenfolge ist bei entsprechender Einstellung (nocycle) zwar eindeutig, aber nicht unbedingt fortlaufend. Grnde dafr sind die schon erwhnte bzw. gezeigte Zweckentfremdung des Zhlers, die Verwendung des gleichen Generators fr verschiedene Tabellen aber auch eine nicht zu Ende gefhrte Einfgetransaktion kann solche Lcken hervorrufen, denn die vergebenen Nummern werden im Unterschied zu den eigentlichen Datenstzen natrlich nicht zurckgerollt.

2.2.13 Log Materialisierte View (Snapshot logs)


Wie Sie sicher schon bemerkt haben drften, benutze ich zumindest in den berschriften neben den englischsprachigen Bezeichnungen der Objekte auch die deutschsprachige Benennung, die Sie beispielsweise im DBA Studio der 8i-Version finden. Bisher fand ich die bersetzungen eigentlich gar nicht so schlecht, aber die berschrift dieses und des nchsten Abschnitts sind meiner Meinung nach schon etwas schrg. Genau wie die schon kurz beschriebenen Refresh groups wird auch dieses Schema-Objekt im Zusammenhang mit den sogenannten Snapshots interessant und daher erst im nchsten Kapitel eingehender behandelt. Bei den Snapshot logs, die mit Hilfe der Anweisungen create snapshot log bzw. drop snapshot log angelegt bzw. wieder gelscht werden handelt es sich um ein Protokoll, mit dem die Replizierung verteilter Daten beschleunigt werden kann. Allerdings steht Ihnen das Feature nur zur Verfgung, wenn Ihr Datenbankserver ber die Option Advanced replication (vgl. Kapitel 2.1) verfgt, was Sie bei Bedarf mit Hilfe der View v$option abfragen knnen.

2.2.14 Materialisierte View (Snapshots)


Das Snapshot-Objekt liefert Ihnen eine Kopie, eben einen Schnappschuss, einer Tabelle aus einer anderen Datenbank. In der Oracle-Dokumentation wird dieses gesamte Thema unter dem Begriff Replication (Replikation) gefhrt. Sie finden hierzu sogar einen eigenen Link Oracle8 Replication. Daneben finden Sie auch eine ausfhrliche Beschreibung bzw. ein eigenes Kapitel im Buch Oracle8 Concepts. Unter Replikation versteht man nun zunchst einmal den Prozess zur Verwaltung von gemeinsamen Daten auf verschiedenen Datenbanken (vgl. Abb. 2.8). In einem solchen verteilten System existieren blicherweise mehrere Kopien gleicher Daten und es geht jetzt um Mechanismen und Werkzeuge, diesen Zustand zum einen zu erreichen und zum anderen auch zu erhalten. Den Zustand zu erreichen heit konkret, dass Sie ein Verfahren bentigen, um auf einfache Weise eine Kopie der Daten aus einer anderen Datenbank zu bekommen und Erhalten bedeutet, diese Kopie wenigstens von Zeit zu Zeit zu aktualisieren.

Beschreibung der Objekte

161

Update Abfrage
db01
Tabelle xxx (Kopie)

db02
Tabelle xxx

Replikation

(Master)

Abbildung 2.8: Verwendung einer nur lese Kopie

Wie Sie der Abbildung 2.8 entnehmen knnen geht es manchmal auch darum, aus einem bisher linearen Prozess zwischen Datenabfrage und Aktualisierung eine Art Kreisverkehr zu bauen. Datennderungen werden zunchst in der Mastertabelle, die sich in der db02-Datenbank befindet, ausgefhrt und ber den Replikationsprozess in der lokalen Kopie zurckerwartet. Ich finde, dass sich da die Frage stellt, warum man sich so etwas antut. Ein wesentlicher Grund fr eine solche Konstruktion heit schlicht und ergreifend Performance. Wie Sie schon wissen, besteht als Alternative fr den Zugriff auf die Tabelle einer anderen Datenbank auch die Verwendung einer Datenbankverknpfung (vgl. Database links). Wie Sie aber spter noch bei den Abfragen bzw. beim Abfragetuning sehen werden, kann die Verwendung einer Datenbankverknpfung bei gleichzeitiger Benutzung verschiedener lokaler und entfernter Tabellen den Zugriffsgau auslsen. Dahingegen ist die Verwendung bzw. Ausfhrung einfacher nderungsabfragen (Einfgen, ndern und Lschen einzelner Datenstze) auch in der verknpften Datenbank immer schnell. Auch der nchste Grund resultiert aus Geschwindigkeitsaspekten. Sie knnen das schnellste Dialogsystem lahm legen, wenn Sie gleichzeitig nur gengend Hintergrundprozesse wie Reports oder Batch-Jobs starten. Im Extremfall kann es daher sinnvoll sein, fr diese Reports und Batch-Jobs eine eigene Datenbank, vielleicht sogar auf einem eigenen Server, zu installieren, zumal die meisten der mir bekannten Reports und Batch-Jobs auch mit tagesaktuellen Daten zurechtkmen. In dem Fall msste man also eine Datenbank erstellen, die im Wesentlichen nur aus Snapshots bzw. Kopien der eigentlichen Tabellen aus der primren Dialogdatenbank besteht. Diese Kopien mssten dann im Rahmen eines tglichen Replikationsverfahrens aktualisiert werden. Als dritten und letzten Grund mchte ich einen Aspekt einfhren, der diesmal nicht auf Geschwindigkeit und damit auf technischen Grnden beruht, sondern aus organisatorischen Manahmen resultiert.

162

Datenbankobjekte in einer Oracle-DB

Es gibt viele Beispiele, wo zentrale Steuerungstabellen wie Kostenstellen, Preise, Artikelsortimente usw. zunchst innerhalb eines bestimmten Fachbereichs so lange optimiert werden, bis eine oder alle diese Tabellen der eigentlichen Anwendungsdatenbank zur Verfgung gestellt werden sollen. In dem Fall wrde auch unser Kreisverkehr aus Abbildung 2.8 aufbrechen, da in solchen Fllen die Endanwender sowieso nur eine Leseberechtigung auf diese speziellen Tabellen haben. Die zentralen Steuerungstabellen wrden vielleicht sogar mit Hilfe einer speziellen Anwendung aufbereitet und bei Bedarf ber den Replikationsprozess verteilt werden. In all den bisher von mir genannten Beispielen war jedoch immerhin noch die Datenquelle und die Kopie eindeutig zu bestimmen. Dieses in Bezug auf die Administration sicherlich einfachere Verfahren wird innerhalb der Oracle-Dokumentation unter dem Begriff Basic Replication abgehandelt. Daneben existiert auch noch das als Advanced Replication beschriebene Verfahren, das eine echte verteilte Datenhaltung bzw. Bearbeitung ermglicht. Hierbei knnen die verteilten Tabellen in jeder Datenbank gendert werden und es ist quasi Sache der Datenbank, fr einen entsprechenden Abgleich zu sorgen und bei Bedarf die notwendigen Aktualisierungen durchzufhren (vgl. Abb 2.9).

Abfrage / ndern db01


Tabelle xxx

Abfrage / ndern db02


Tabelle xxx

Replikation

Abbildung 2.9: Verteilte Datenhaltung mit berkreuzreplikation

Natrlich sind bei dem in Abbildung 2.9 skizzierten Verwahren Konflikte in Form von Datenkollisionen vorprogrammiert, es sei denn man hat das Glck, dass die verteilte Datenhaltung bei nherer Betrachtung eigentlich nur ein technisches Feature ist, denn aufgrund organisatorischer Manahmen werden die Daten immer nur getrennt bearbeitet. Ein gutes wenn auch schon leicht abgenutztes Beispiel hierfr ist immer der lnderbergreifend operierende Konzern. Vor allem aus Grnden der Zugriffsgeschwindigkeit wird mindestens in jedem Land, wenn nicht sogar in jedem greren Standort eine eigene Datenbank installiert. Und damit alle Anwendungsteile und Reports berall laufen, sollen in jeder Datenbank jeweils alle Daten gespeichert werden.

Beschreibung der Objekte

163

Da aber aufgrund organisatorischer Manahmen beispielsweise deutsche Kunden nur direkt in der deutschen Datenbank bzw. brasiliansiche Kunden nur im dortigen Standort mit der dort vorhandenen lokalen Datenbank bearbeitet werden, ist eine Datenkollision bei der Replikation nicht zu erwarten. Beispiele Um den Bogen nicht zu berspannen, mchte ich hier und jetzt nur die einfache Replikation an einem Beispiel demonstrieren. Dabei begngen wir uns auch damit, dass wir selbst fr die Aktualisierung der kopierten Daten sorgen mssen, d.h. ich verzichte ebenfalls auf die Einrichtung eines entsprechenden SNP-Hintergrundprozesses. Um mit Snapshots arbeiten zu knnen, bentigen Sie in der Regel wenigstens zwei Datenbanken. Wenn Sie bisher dem roten Faden des Buches gefolgt sind, dann haben Sie die orcl-Starterdatenbank und unsere selbstdefinierte Datenbank db01 zur Verfgung, wobei Sie das Beispiel natrlich auch mit beliebigen anderen Datenbanken ausprobieren knnen. Zunchst einmal muss im ersten Schritt die Mastertabelle angelegt werden. Hierzu definieren wir in der orcl-Datenbank die Tabelle lohnarten (vgl. Listing 2.33) und fgen in ihr anschlieend eine Reihe von Datenstzen ein.
drop table lohnarten; / create table lohnarten ( la varchar2(3), la_text varchar2(55), constraint lohnarten_pk primary key (la)) tablespace usr; commit; insert into insert into insert into insert into insert into insert into insert into insert into commit; lohnarten lohnarten lohnarten lohnarten lohnarten lohnarten lohnarten lohnarten values values values values values values values values ('100', ('110', ('120', ('200', ('210', ('300', ('310', ('400', 'Grundgehalt'); 'Freiw. Zulage'); 'Sonstige Zulage'); 'berstunden'); 'Pauschalausgleich berstunden'); 'Sonderzahlung'); 'Bonus'); 'Direktversicherung');

Listing 2.33: Anlegen und Fllen der Mastertabelle

Die Lohnartentabelle hat einen recht einfachen Aufbau. Sie besteht nur aus einem eindeutigen Schlssel, der Lohnart, und einer Bezeichnung. Das war zunchst auch schon alles, was in der orcl-Masterdatenbank zu tun ist. Die jetzt folgenden Arbeitsschritte mssen wieder in der db01-Datenbank durchfhrt werden. Dort sorgen wir als Nchstes fr die gewnschte Kopie der Lohnartentabelle und legen hierzu einen entsprechenden Schnappschuss (vgl. Listing 2.34) an.

164

Datenbankobjekte in einer Oracle-DB

drop snapshot lohnarten; create snapshot lohnarten tablespace usr refresh force as select * from lohnarten@oralink; / commit;
Listing 2.34: Anlage des lohnarten-Schnappschusses

Wie Sie sehen, hnelt die Definition des Schnappschusses in gewisser Weise der Anlage einer Tabelle. Neben einem Namen knnen Sie den verwendeten Tablespace und wenn es denn sein muss, sogar eine eigene Speicherbelegungsregel (storageKlausel) vergeben. Was sich von der Anlage einer Tabelle unterscheidet, ist allerdings die Definition des Inhalts, denn der ergibt sich aufgrund einer spezifizierten Abfrage. In unserem Beispiel erstellen wir aufgrund der verwendeten Abfrage eine vollstndige Kopie der Lohnartentabelle, die wir mit Hilfe des Datenbanklinks oralink aus der Quelldatenbank abholen. Wenn Sie nun vermuten, dass Sie hier anstelle derartig einfacher Ausdrucke auch durchaus komplexere Abfragen verwenden knnen, dann haben Sie Recht. Aus dem Grund erfolgt die Vorgabe der zu verwendenden Abfrage im Schema-Manager auch nicht in der bisher gewohnten formatgebunden Weise, sondern hierfr stellt Ihnen das Programm ein schlichtes mehrzeiliges Textfeld zur Verfgung, indem Sie die ntige Abfrage formatfrei eingeben knnen. Wichtig fr die Funktionsweise des Snapshot-Objekts ist die verwendete refreshKlausel, die festlegt, auf welche Weise der Schnappschuss im Bedarfsfall aktualisiert wird. Die in meinem Beispiel verwendete Variante force bemht sich, den Schnappschuss optimal wiederherzustellen. Konkret heit das, dass Oracle zunchst versucht, lediglich die nderungen zu bertragen was der Option fast entspricht. Ist das nicht mglich (zum Beispiel weil kein Snapshot Log vorliegt), dann wird der gesamte Schnappschuss neu aufgebaut, was der Option complete entspricht, d.h. mit der Klausel refresh complete wrde das Snapshot-Objekt grundstzlich komplett aktualisiert. Die force-Variante wird von Oracle im brigen standardmig verwendet, wenn Sie die refresh-Klausel beim Anlegen des Snapshot-Objekts weglassen. Das somit erzeugte Schnappschuss-Objekt knnen Sie eigentlich wie eine gewhnliche Tabelle verwenden, d.h. es kann selbst wieder in jeder denkbaren Abfrage verwendet werden. Damit solche Abfragen gerade auch bei greren Kopien schn schnell sind, knnen Sie fr den Schnappschuss auch beliebige Indices definieren, wie Sie auch dem folgenden Beispiel entnehmen knnen.
create index lohnarten_i on snap$_lohnarten (la_text);

Ist das nicht ein merkwrdiger Tabellenname, den ich bei der Anlage des Index verwendet habe? In der Tat fhrt die Definition des Snapshot-Objekts zu einer Reihe von Hintergrundaktivitten. Zum einen wird fr den gewhlten Schnappschuss eine zugehrige Tabelle angelegt, die zusammen mit dem Prfix snap$_ den glei-

Beschreibung der Objekte

165

chen Namen erhlt. Dabei wird ein in der Quelle definierter Primrschlssel ebenfalls bernommen bzw. fr die Schnappschusstabelle angelegt. Daneben legt Oracle auch eine View mit dem gleichen Namen des SnapshotObjekts an, wobei die blicherweise fr den eigentlichen Zugriff auf die kopierten Daten verwendet wird. Letztendlich erhalten Sie im Schema natrlich auch noch das eigentliche Schnappschuss-Objekt, in dem die Herkunft der Daten und die gewnschten Aktualisierungsregeln gespeichert werden. Nachdem nun der Schnappschuss erstellt wurde, knnen wir die kopierten Daten in unserer Datenbank ganz gewhnlich verwenden, indem wir beispielsweise eine Abfrage der vorhandenen Lohnarten erstellen.
SQLWKS> select * from lohnarten 2> LA LA_TEXT --- ------------------------------------------------------100 Grundgehalt 110 Freiw. Zulage 120 Sonstige Zulage 200 berstunden 210 Pauschalausgleich berstunden 300 Sonderzahlung 310 Bonus 400 Direktversicherung 8 rows selected.

Kehren wir nun noch einmal zu unserer Abbildung 2.8 zurck, dann als Nchstes wollen wir das dort skizzierte Verfahren nachstellen. Hierzu mssen Sie zuerst eine nderung in der Mastertabelle durchfhren und danach die Aktualisierung des Schnappschusses einleiten (vgl. Listing 2.35). Die hierzu notwendigen SQL-Befehle finden Sie im folgenden Beispiel.
insert into lohnarten@oralink values ('900','Auszahlung'); commit; execute dbms_snapshot.refresh('lohnarten');
Listing 2.35: nderung der Mastertabelle und auffrischen der Kopie

Mit Hilfe der ersten Anweisung fgen wir in der Mastertabelle einen neuen Datensatz mit der Lohnart 900 ein. Damit diese nderung auch in unserer Datenbank sofort sichtbar wird, lsen wir die Aktualisierung des Schnappschusses aus, indem wir die refresh-Prozedur aus dem dbms_snapshot-Paket aufrufen. Die Prozedur erhlt als ersten Parameter den Namen oder eine Liste der zu aktualisierenden Schnappschsse. Was ich hier gezeigt habe, ist die einfachste Verwendungsform dieser Paketprozedur, die fr spezielle Aufgaben noch weitere Parameter erhalten kann. Auerdem enthlt das Paket neben der refresh-Prozedur auch noch weitere Funktionalitten. Wenn es Sie interessiert, dann finden Sie eine weitergehende Beschreibung des Paketes in der Dokumentation Oracle8 Replication im Kapitel Replication Management API Reference.

166

Datenbankobjekte in einer Oracle-DB

Snapshot Logs Ein sogenannter Snapshot Log (soll ich lieber Log der materialisierten View sagen) ist eine spezielle Tabelle, in der die in der Mastertabelle durchgefhrten nderungen aufgezeichnet werden, d.h. dieser Log-Bereich wird in der gleichen Datenbank wie die Mastertabelle angelegt. Bei einer spteren angeforderten Aktualisierung eines Schnappschusses kann Oracle dieses Protokoll verwenden, um im Rahmen des Snapshot-Refreshs nur die genderten Stze zu bertragen. Es liegt auf der Hand, dass eine solche Verfahrensweise (fast refresh) blicherweise wesentlich schneller abluft als eine vollstndige Wiederherstellung der Kopie (complete refresh). Die Anlage eines solchen Logs ist denkbar einfach und erfolgt, wie Sie dem folgenden Beispiel entnehmen knnen, mit Hilfe der Anweisung create snapshot log.
drop snapshot log on lohnarten; create snapshot log on lohnarten tablespace usr; commit;

Da beim Snapshot Log wieder Daten in einer speziellen Tabelle gespeichert werden, haben Sie die Mglichkeit, den zu verwendenden Tablespace und bei Bedarf auch eine eigene storage-Klausel vorzugeben. Die hinter dem Log liegende Tabelle heit brigens wie die Mastertabelle, erhlt jedoch zustzlich den Prfix mlog$_ (z.B. mlog$_lohnarten). Probieren wir das ganze einfach mal aus. Wechseln Sie hierzu in die orcl-Datenbank und erstellen Sie dann als erstes wie oben beschrieben das Snapshot Log fr die Tabelle lohnarten. Fgen sie anschlieend eine neue Lohnart in die Mastertabelle ein.
insert into lohnarten values ('800','Kindergeld');

Wenn Sie danach einfach mal eine Abfrage auf die Tabelle des Snapshot Logs ausfhren, dann erhalten Sie als Ergebnis genau die eben eingefgte Lohnart.
SQLWKS> select * from mlog$_lohnarten 2> LA SNAPTIME$$ D O CHANGE_VECTOR$$ --- -------------------- - - --------------800 01-JAN-00 I N FE 1 row selected.

Wechseln Sie nun in die andere Datenbank und fhren Sie danach die Aktualisierung des Schnappschusses durch und kontrollieren Sie danach noch einmal die Log-Tabelle. Die enthlt jetzt keine Daten mehr, da sie nach einer durchgefhrten Aktualisierung automatisch gelscht wird. Refresh Groups Wie schon angedeutet, mssen die einzelnen Snapshots nicht unbedingt einzeln aktualisiert werden, sondern Sie haben auch die Mglichkeit, diesen Vorgang zu automatisieren oder zumindest in Gruppen zu organisieren. Selbst in unserem ein-

Beschreibung der Objekte

167

fachen Beispiel wre es denkbar, das fr die Mastertabelle nicht nur einer, sondern mehrere Schnappschsse mit jeweils unterschiedlichen Abfragen existieren. In dem Fall mssten Sie nach einer nderung alle Schnappschsse aktualisieren, um in jeder dieser Tabellen den gleichen Stand zu haben. Das ginge zwar auch mit Hilfe eines einzigen dbms_snapshot-Befehls, jedoch liegt das eigentliche Problem darin, immer genau zu wissen welche Schnappschsse gerade berhaupt zu aktualisieren sind. Aus diesem Grund knnen Sie zusammenhngende Snapshot-Objekte zu einer logischen Gruppe zusammenfassen und erhalten hierdurch die Mglichkeit, im Bedarfsfall die Aktualisierung der gesamten Gruppe zu veranlassen. Auch das mchte ich im Rahmen eines kleinen Beispiel darstellen. Hierzu erzeugen wir uns zunchst ein weiteres Snapshot-Objekt, das ebenfalls auf der Mastertabelle lohnarten basiert.
drop snapshot lohnarten1; create snapshot lohnarten1 tablespace usr refresh force as select * from lohnarten@oralink where la > '900'; / commit;

Wenn Sie nun wieder entsprechend der gezeigten Vorgehensweise im Listing 2.35 in der Mastertabelle eine weitere Lohnart (z.B. 901, berweisung) einfgen, dann wird zwar die Kopie lohnarten aktualisiert, aber der neue Schnappschuss lohnarten1 wird, wie eigentlich nicht anders zu erwarten war, eben nicht aufgefrischt. Hierzu htten Sie in der refresh-Anweisung beide Schnappschsse spezifizieren mssen.
execute dbms_snapshot.refresh('lohnarten1,lohnarten');

Um nun die gemeinsame Auffrischung dieser beiden Kopien zu vereinfachen, legen wir hierzu die Refresh Group lohnarten an. Wie schon angedeutet, erfolgt die Anlage einer solchen Gruppe mit Hilfe der make-Prozedur aus dem dbms_refresh-Pakets, wobei Sie die genaue Beschreibung des Pakets ebenfalls wieder im Kapitel Replication Management API Reference finden. Die Prozedur erwartet eine Reihe von Parametern, weshalb es nicht schadet, sich zumindest das zugehrige SQL-Skript mit Hilfe des Schema-Managers zu erzeugen. Der zugehrige Dialog im Schema-Manager besteht aus zwei Registerkrtchen. Auf der ersten Seite (vgl. Abb. 2.10) mssen Sie die generellen Daten der neuen Gruppe, wie beispielsweise den Namen, das zugehrige Schema oder das Intervall fr eine eventuelle automatische Aktualisierung vorgeben. Entsprechend dem eingedeutschten Sprachgebrauch des deutschen 8i-Clients mssen Sie jetzt natrlich eine neue Abgleichengruppe anlegen, (vgl. Abb. 2.11) was allerdings genauso funktioniert, da es schlielich ja auch das Gleiche ist.

168

Datenbankobjekte in einer Oracle-DB

Abbildung 2.10: Definition einer neuen Refresh Group

Abbildung 2.11: Erstellen einer Abgleichengruppe in der 8i-Version

Mit Hilfe des zweiten Registerkrtchens (vgl. Abb. 2.12) erfolgt die Zuordnung der einzelnen Snapshots zu der neuen Gruppe. Hierbei finden Sie im unteren Fensterteil eine Liste aller vorhandenen und noch nicht zugeordneten Schnappschussdefinitionen und in der oberen Liste befinden sich die zur Gruppe gehrenden SnapshotObjekte.

Beschreibung der Objekte

169

Abbildung 2.12: Zuordnen der bentigten Snapshots

Nach Eingabe aller Definitionen knnen Sie die neue Gruppe mit Hilfe der CreateSchaltflche erzeugen, oder Sie fhren das zugehrige SQL-Skript (vgl. Listing 2.36) mit Hilfe eines beliebigen SQL-Editors in der Datenbank aus.
begin dbms_refresh.make('"SYSTEM".lohnarten', '"SYSTEM"."LOHNARTEN", "SYSTEM"."LOHNARTEN1"', NULL, '', FALSE, TRUE, 0, 'RB0', FALSE, FALSE ); commit; end;
Listing 2.36: Anlegen einer Aktualisierungsgruppe

Die Aktualisierung aller zur Gruppe gehrnenden Schnappschsse erfolgt jetzt mit Hilfe der refresh-Prozedur des dbms_refresh-Pakets, deren Verwendung Sie dem nchsten Beispiel entnehmen knnen.
insert into lohnarten@oralink values ('907','VL-3'); commit; execute dbms_refresh.refresh('LOHNARTEN'); commit;

Das Lschen einer solchen Aktualisierunggruppe erfolgt auch mit Hilfe des Pakets dbms_refresh und zwar genau mit der dort enthaltenden Prozedur destroy.
execute dbms_refresh.destroy('LOHNARTEN'); commit;

170

Datenbankobjekte in einer Oracle-DB

Varianten Snapshots bzw. vor allem die Snapshot Logs knnen nicht nur im Rahmen der ganz am Anfang beschriebenen Beispiele und Herausforderungen bei verteilter Datenhaltung verwendet werden, sondern gerade bei den Logs ergeben sich noch andere Einsatzgebiete. Das ist wie im richtigen Leben: mit einem Feuerzeug knnen sie eine Kerze anznden oder eine Flasche Bier ffnen; erfunden wurde das Feuerzeug wohl eher fr die Kerze und dennoch ist es fr die andere Aufgabenstellung auch ein prima Werkzeug. Im Folgenden erhalten Sie vielleicht ein paar Anregungen fr die zweckentfremdete Verwendung dieses Oracle-Werkzeugs.

Stichtagsbestnde Gerade bei Statistiken ist es oft strend, wenn deren Ergebnis mehr oder weniger zufllig vom Datum und der Uhrzeit des Programmstarts abhngt. Aus dem Grund werden fr solche Auswertungen oftmals spezielle Stichtagsbestnde der bentigten Daten bereitgestellt. Diese Bestnde werden anschlieend nur noch kontrolliert gendert, beispielsweise jeweils am Monatsende. Bevor Sie nun lange ber Programme und Verfahren zur Produktion solcher Stichtagsbestnde nachdenken, sollten Sie einmal berlegen, ob Sie diese Bestnde nicht mit Hilfe von Snapshots liefern knnen. Wenn Sie nun glauben, das ginge nicht, weil die Stichtagsbestnde in der selben Datenbank wie die Mastertabellen liegen, dann liegen Sie falsch, denn Snapshots knnen auch fr Tabellen in der gleichen Datenbank angelegt werden, d.h. die Verwendung von Daten aus anderen Datenbanken ist keine zwingende Option. nderungsdienst Wer schon einmal Schnittstellen geschrieben hat, der wei, dass vor allem bei groen Datenmengen irgendwann einmal die Bestellung auf dem Tisch liegt, nur noch genderte Datenstze zu liefern. Nichts ist einfacher als das, denn in dem Fall legen Sie fr diese Tabellen einfach jeweils ein Snapshot Log an. Anschlieend besitzen Sie fr Ihr Schnittstellenprogramm fr jede zu liefernde Tabelle eine Liste allen genderten oder gelschten Primrschlsseln und genau die bertragen Sie anschlieend auch nur noch. Danach lschen Sie die Snapshot Logs, so dass Sie beim nchsten Schnittellenlauf wieder nur noch neue nderungen bertragen. In der Tabelle des Snapshot Logs finden Sie das Feld dmltype$$. Dieses Feld enthlt die Wert I, U und D, wenn der in der Mastertabelle zugehrige Datensatz eingefgt (insert), gendert (update) oder gelscht (delete) wurde.

2.2.15 Synonym (Synonyms)


Endlich mal wieder ein einfaches Schema-Objekt ohne tieferen Hintergrund oder besonderer Tragweite. Was dieses Objekt macht bzw. wozu es dient, wird eigentlich schon mit der berschrift des Kapitels aussagekrftig beschrieben: Es geht um die Definition von Alternativbegriffen fr vorhandene Schema-Objekte.

Beschreibung der Objekte

171

Bisher haben wir im Rahmen dieses Workshops die verschiedenen Schema-Objekte mit Hilfe irgendeines Benutzers (z.B. system) angelegt und anschlieend einfach unter dem verwendeten Namen angesprochen. Dadurch, dass wir die ganze Zeit mit der Benutzer-Id des Objektbesitzers gearbeitet haben, konnten wir die angelegten Objekte demzufolge ohne besondere Qualifizierung verwenden. Das ist aber ein spezieller Luxus, den normalerweise nur der Objekte-Eigentmer geniest, denn der vollstndige Zugriffspfad auf ein Objekt beginnt immer mit dem Namen des zugehrigen Schemas. Hiernach folgt als Trennzeichen ein Punkt (.) und erst dann kommt der eigentliche Name des Objekts (<Schema>.<Objektname>). Nun haben wir aber in den bisherigen Beispielen oftmals, vielleicht sogar ohne es zu wissen, Objekte verwendet, die bei genauerem Hinschauen Eigentum anderer Benutzer bzw. Schemata sind. Beispiele hierfr sind zum einen die schon mehrfach verwendeten dbms-Pakete oder v$-Views, die eigentlich alle dem Benutzer sys gehren bzw. dem gleichnamigen Schema zugeordnet sind. Das wir hierauf aber bisher keine Rcksicht nehmen mussten liegt einfach daran, dass fr diese Objekte in der Datenbank Synonyme, Aliasnamen oder Alternativbezeichnungen, oder welchen Begriff Sie auch immer dafr verwenden mchten, definiert sind. Bei der Anlage solcher Synonyme gibt es prinzipiell zwei Strategien. Zum einen knnen Sie beispielsweise in Ihrem aktuellen Schema ein Synonym fr ein Objekt aus einem anderen Schema oder sogar einer anderen Datenbank anlegen. Zum anderen knnen Sie ffentliche (public) Alternativbezeichnungen definieren, so dass das zugrundeliegende Objekt bei entsprechenden Zugriffsrechten grundstzlich auch ber seinen Aliasnamen angesprochen werden kann. Die Anlage solcher Synonyme erfolgt grundstzlich mit Hilfe der Anweisung create synonym und das Lschen der Alternativbezeichnung knnen Sie mit dem Befehl drop synonym veranlassen. Doch genug der Theorie, mit Hilfe eines einfachen Beispiels soll das Ganze nun wieder veranschaulicht werden. Beispiele Im letzten Kapitel haben Sie mit Hilfe des Datenbanklinks oralink hufiger die Tabelle lohnarten aus einer anderen Datenbank abgefragt. Stellen wir uns nun vor, diese Aufgabe stnde regelmig ins Haus und Sie htten irgendwann keine Lust mehr, immer an die korrekte Vorgabe des Links zu denken. In dem Fall knnten Sie sich fr die Tabelle aus der anderen Datenbank ein Synonym anlegen und die Tabelle anschlieend in jeder Abfrage nur noch ber den vergebenen Aliasnamen ansprechen (vgl. Listing 2.37).
drop synonym r_lohnarten; create synonym r_lohnarten for system.lohnarten@oralink; commit;
Listing 2.37: Anlage des Synonyms r_lohnarten

172

Datenbankobjekte in einer Oracle-DB

In dem Beispiel legen Sie fr die in der orcl-Datenbank angelegte Tabelle system.lohnarten in Ihrem eigenen Schema die Alternativbezeichnung r_lohnarten an. Folglich knnen Sie von nun an in allen Abfragen diese neue Tabellenbezeichnung verwenden.
select * from r_lohnarten; -- mit Synonym select * from system.lohnarten@oralink; -- ohne Synonym

Das war also ein Beispiel fr die Anlage eines Synonyms im eigenen Schema, wo durch dessen Verwendung die eigene Arbeit ein wenig vereinfacht wurde. Im nchsten Fall geht es um die Anlage eines ffentlichen Synonyms. Nehmen wir an, Sie sind von dem im Kapitel 2.2.8 erstellten tollhaus-Paket so begeistert, dass Sie den Zugriff auf die dort enthaltenen Funktonalitten fr andere Benutzer vereinfachen mchten, wozu sich ein ffentlicher Aliasname anbietet.
drop public synonym tollhaus; create public synonym tollhaus for system.tollhaus; commit;

Anschlieend knnen alle Benutzer mit Zugriff auf das tollhaus-Paket dieses beim Aufruf verwenden, als wenn es ihr eigenes wre.
select tollhaus.spiegeln(parameter) from v$option; -- mit Synonym select system.tollhaus.spiegeln(parameter) from v$option; -- ohne Synonym

2.2.16 Tabellentyp (Table Types)


Willkommen zurck bei den Objekten. Wir sind nun innerhalb der SchemaObjekte bei der letzten objektorientierten Kategorie angelangt, die Sie damit wieder nur dann sehen, wenn Ihr Datenbankserver ber die Objekte-Option verfgt. Genau wie bei den schon beschriebenen Array Types geht es auch jetzt wieder darum, sogenannte Kollektionen (Collections) zu verwalten. Im Unterschied zu den Datenfeldern, bei denen es um die Anlage einer festen Anzahl von Elementen ging und die aus Sicht der Tabelle in einer einzigen Spalte gespeichert wurden, werden die gleich besprochenen Kollektionen in einer separaten Tabelle abgelegt und ber interne Verweise angesprochen. Dadurch ist die Anzahl der in der Kollektion gespeicherten Elemente nicht mehr festgelegt, d.h. sie kann im beliebigen Rahmen und vor allem von Fall zu Fall variiert werden. Mit Hilfe einer Kollektion beschreibt man blicherweise eine Liste gleichartiger Elemente. Bleiben wir bei unserem letzten Objekt-Beispiel mensch, wofr Kollektionen fr die Objekte Autos, Bcher oder sonstige gleichartige Besitztmer aber auch Aufzhlungen fr Urlaubsreisen, Seminare oder hnliches denkbar wren. In der klassischen relationalen Beschreibung entspricht jede dieser Kollektionen einer separaten (Child-Tabelle) meistens mit gleichem Schlssel plus mindestens einem weiteren Hilfsschlssel zur Identifizierung jedes Eintrags (vgl. Abb 2.13).

Beschreibung der Objekte

173

Mensch

0:n

Autos

0:n

Bcher

0:n

Reisen

Abbildung 2.13: Kollektionen fr das Objekt mensch

Die Erstellung der hier besprochenen Sammlungen erfolgt wieder mit einer Variante des Befehls create type, d.h. bei dem Befehl handelt sich hierbei um eine sehr universelle Anweisung, mit der insgesamt die drei verfgbaren objektorientierten Schema-Eintrge erstellt werden knnen. Beispiele In unserem Beispiel mchte ich das Ganze an dem oben beschriebenen Buchbeispiel demonstrieren, d.h. wir erstellen fr jeden Menschen eine Sammlung der ihm gehrenden Exemplare. Damit das Ganze einfach und bersichtlich bleibt, speichern wir fr jedes Buch lediglich den Titel und den Anschaffungspreis. Hierzu legen wir als Erstes ein weiteres Objekt mit dem Namen buch an, das neben den eben genannte Eigenschaften noch eine laufende Nummer zur Identifizierung erhlt (vgl. Listing 2.38).
create type lfdnr titel wert commit;
Listing 2.38: Anlage des neuen Objekts buch

buch as object ( number, varchar2(50), number ) ;

Hierdurch erhalten wir zunchst aber nur wieder eines neues Objekt der Kategorie Object Type. Erst im nchsten Schritt entsteht durch die erneute Verwendung des create type-Befehls endlich der neue Objekttyp Table Type.

174

Datenbankobjekte in einer Oracle-DB

create type buchliste as table of buch; commit;

Jetzt verfgen wir also ber ein Objekt, mit dem eine Sammlung von Bchern beschrieben werden kann, d.h. jedes in der Sammlung enthaltene Element entspricht dabei dem Datentyp bzw. dem Objekt buch. Der nchste Schritt besteht nun darin, unser bestehendes Objekt mensch entsprechend zu erweitern. Normalerweise geht das immer mit Hilfe einer Anweisung der Art create or replace type. Was in unserem Fall dabei allerdings passieren wird, dass knnen Sie dem Listing 2.39 entnehmen.
SQLWKS> create or replace type mensch as object ( 2> name varchar2(30), 3> vname varchar2(30), 4> strasse varchar2(30), 5> plz varchar2(5), 6> ort varchar2(30), 7> geschl varchar2(1), 8> gebdat date, 9> 10> buecher buchliste, 11> 12> member function g_alter return number, 13> pragma restrict_references(g_alter, wnds, wnps), 14> 15> member function g_anschrift return number, 16> pragma restrict_references(g_anschrift, wnds, wnps), 17> 18> member function g_buchzahl return number, 19> pragma restrict_references(g_buchzahl, wnds, wnps) ); create or replace type mensch as object ( * ORA-02303: cannot drop or replace a type with type or table dependents
Listing 2.39: Misslungener Versuch, das vorhandene Objekt zu erweitern

Die Weigerung von Oracle, das schon vorhandene Objekt aufgrund von existierenden Abhngigkeiten zu erweitern, ist im brigen nicht nur auf selbstdefinierten Typen bzw. Objekte beschrnkt, sondern so etwas kann Ihnen auch beim nachtrglichen ndern von gewhnlichen Tabellen passieren. Was nun folgt, entspricht daher auch immer dem gleichen Schema. Zunchst wird fr die alte Tabelle eine Sicherungskopie angelegt, dann wird die Tabelle neu definiert und anschlieend unter Bercksichtigung der neuen Struktur zurckkopiert. In unserem konkreten Fall ergibt sich folgendes Szenario: 1. Entladen der Tabelle menschen in eine Hilfstabelle 2. Tabelle menschen lschen. Hierdurch wird das Objekt mensch freigegeben. 3. Objektdefinition mensch ndern.

Beschreibung der Objekte

175

4. Tabelle menschen neu anlegen. 5. Tabelle zurckkopieren. 6. Hilfstabelle bzw. Sicherungskopie lschen. Das Listing 2.40 zeigt die notwendigen Anweisungen zur Erledigung des ersten Arbeitsschritts. Zunchst wird eine gewhnliche Tabelle mit all den notwendigen Feldern erstellt. Diese Tabelle wird klassisch und nicht mit Hilfe des mensch-Objekts angelegt, da ansonsten die mit dem Objekt mensch verbundenen Abhngigkeiten nicht entfernt, sondern nur verschoben wrden.
drop table h_mensch; / create table h_mensch ( name varchar2(30), vname varchar2(30), strasse varchar2(30), plz varchar2(5), ort varchar2(30), geschl varchar2(1), gebdat date ) tablespace usr; commit; insert into h_mensch select name, vname, strasse, plz, ort, geschl, gebdat from menschen commit;
Listing 2.40: Anlegen der Hilfstabelle und Erstellen der Sicherungskopie

Im letzten Teil des Skripts werden die Daten in die neue Tabelle kopiert, womit der erste Teil der Aufgabe erledigt wre, doch wie heit es so schn: dieses war der erste Streich, doch der zweite folgt sogleich...
drop table menschen; commit;

Nach Eingabe der eben abgebildeten Befehle ist die Tabelle menschen gelscht, wodurch das Objekt mensch zum ndern freigegeben wird, so dass Sie den dritten Arbeitsschritt einleiten und das Objekt in der gewnschten Weise ndern knnen (vgl. Listing 2.41).
create or replace type mensch as object ( name varchar2(30), vname varchar2(30), strasse varchar2(30), plz varchar2(5), ort varchar2(30), geschl varchar2(1),

176

Datenbankobjekte in einer Oracle-DB

gebdat date, buecher buchliste, member function g_alter return number, pragma restrict_references(g_alter, wnds, wnps), member function g_anschrift return varchar2, pragma restrict_references(g_anschrift, wnds, wnps), member function g_buchzahl return number, pragma restrict_references(g_buchzahl, wnds, wnps) ); / commit;
Listing 2.41: ndern der Objektdefinition mensch

Im Prinzip wird das Objekt im Wesentlichen um die Eigenschaft der Bcherliste erweitert. Zustzlich definieren Sie die neue Methode g_buchzahl, mit der spter einmal die Anzahl der in der Liste gespeicherten Bcher abgerufen werden soll. Nach der Aktualisierung des Objekts kann die darauf basierende Tabelle menschen wieder angelegt werden, allerdings funktioniert das wie Sie gleich sehen werden aufgrund der dort enthaltenen Kollektion etwas anders als vorher.
create table menschen of mensch tablespace usr nested table buecher store as buch_tab; commit;

Diese Anweisung legt zusammen mit der Tabelle menschen implizit noch eine weitere Tabelle buch_tab an, in der die jeweils vorhandene Bchersammlung gespeichert werden soll. Konkret sieht die angelegte Tabelle damit folgendermaen aus:
SQLWKS> desc menschen Column Name Null? ------------------------------ -------NAME VNAME STRASSE PLZ ORT GESCHL GEBDAT BUECHER Type ---VARCHAR2(30) VARCHAR2(30) VARCHAR2(30) VARCHAR2(5) VARCHAR2(30) VARCHAR2(1) DATE RAW(36)

Beschreibung der Objekte

177

Im nchsten Schritt geht es nun um das Zurckladen der Sicherungskopie in unsere neue Tabelle, was wieder mit Hilfe einer gewhnlichen insert-Anweisung passiert.
insert into menschen select name, vname, strasse, plz, ort, geschl, gebdat, buchliste() from h_mensch; commit;

Beachten Sie hierbei allerdings die verwendete Anweisung buchliste(). Diese Anweisung sieht aus wie eine Funktion und verhlt sich eigentlich auch so hnlich. Im objektorientierten Sprachgebrauch bezeichnet man diese Funktion allerdings gewhnlich als Konstruktor. Ein solcher Konstruktor tut was sein Name sagt, d.h. er konstruiert das unter dem selben Namen definierte Objekt. In unserem Beispiel erstellt der Ausdruck also eine Bcherliste. Dabei werden normalerweise die in der Liste zu speichernden Elemente (Bcher) innerhalb der Klammern aufgezhlt, d.h. in unserem konkreten Fall konstruiert der Ausdruck buchliste() einfach nur eine leere Bcherliste. Damit haben wir den fnften Arbeitsschritt abgearbeitet und fahren gleich mit dem sechsten und letzten Schritt, dem Lschen der Sicherungskopie, fort.
drop table h_mensch; commit;

Bevor wir nun fr unser Objekt mensch die neue Methode g_buchzahl erstellen, wollen wir uns einmal an einem Beispiel anschauen, wie die Aktualisierung unserer Datenstze vor allem in Bezug auf die Bcherliste aussehen knnte (vgl. Listing 2.42).
update menschen set buecher = buchliste(buch(1, 'Oracle Workshop', 20)) where name = 'Raymans' and vname = 'Irina'; update menschen set buecher = buchliste(buch(1, 'dBASE fr Fortgeschrittene', 20), buch(2, 'Meine Rezepte', 23)) where name = 'Zschoge'; update menschen set buecher = buchliste(buch(1, 'Donald Duck', 5), buch(2, 'Herr der Ringe', 9.30), buch(3, 'Elementarteilchen', 17.95)) where name = 'Heger'; commit;
Listing 2.42: Aktualisierung der Bcherliste mit Hilfe von update-Anweisungen

178

Datenbankobjekte in einer Oracle-DB

Diese Anweisungen sehen wirklich schlimmer aus als sie sind. Zusammen mit Objekten erzeugt man oft geschachtelte Konstruktionen, die bisher nur bei komplexen ineinandergeschachtelten Funktionsaufrufen mglich waren. Wie schon gesagt, stellt jedes Objekt auch eine namensgleiche besondere Konstruktions-Funktion zur Verfgung mit dem das Objekt gebildet werden kann. Dieser Konstruktor erwartet fr jede Objekteigenschaft einen Parameter und liefert als Ergebnis einen Verweis auf das gebildete Objekt. Dabei definiert das von uns erstellte Objekt buchliste eine unbestimmte Anzahl von Elementen, weshalb die zugehrige Konstruktionsfunktion auch mit einer variablen Anzahl von Parametern verwendet werden kann. Jeder dieser Parameter muss allerdings vom Typ buch sein. Da das wiederum ein Objekt ist, wird ese mit dem zugehrigen Konstruktor buch() erzeugt, der hierzu genau drei Werte fr die entsprechenden Eigenschaften (Lfd.Nr., Titel und Wert) des Buchobjekts bentigt. Der erste Datensatz erhlt mit der Aktualisierungsabfrage also genau ein Buch, wohingegen beim dritten Datensatz eine Buchliste mit drei verschiedenen Bchern konstruiert wird. Jetzt wird es so langsam Zeit fr die Erstellung unsere neue Methode g_buchzahl, was im folgenden Listing 2.43 passiert.
create or replace type body mensch is member function g_alter return number is begin return floor(months_between(sysdate, gebdat) / 12) ; end; member function g_anschrift return varchar2 is anschrift varchar2(2000) := ' '; begin if geschl = 'M' then anschrift := 'Herrn' || chr(10) || chr(13); else anschrift := 'Frau' || chr(10) || chr(13); end if; anschrift := anschrift || vname || ' ' || name || chr(10) || chr(13); anschrift := anschrift || strasse || chr(10) || chr(13); anschrift := anschrift || plz || ' ' || ort; return anschrift; end; member function g_buchzahl return number is begin return buecher.count; end;

Beschreibung der Objekte

179

end; / show errors; commit;


Listing 2.43: Programmierung der neuen Methode g_buchzahl

Wie Sie dem Beispiel entnehmen knnen, stellt die Programmierung der neuen Methode keine grere Herausforderung dar. Alle Kollektionsobjekte besitzen standardmig schon eine Reihe bereitgestellter Methoden, mit deren Hilfe beispielsweise ein Durchblttern und die Verwaltung der Listen mglich ist. Eine dieser Methoden heit count und liefert die Anzahl der in einer Kollektion enthaltenen Elemente.
SQLWKS> select name, gebdat, p.g_alter(), p.g_buchzahl() 2> from menschen p NAME GEBDAT P.G_ALTER( P.G_BUCHZA ------------------------------ ----------------- ---------- ---------Raymans 03-DEC-64 35 0 Raymans 27-DEC-65 34 1 Zschoge 13-JUL-62 38 2 Heger 12-MAY-69 31 3 4 rows selected.
Listing 2.44: Abfrage unserer neuen Struktur unter Verwendung der neuen Methode

Eine Aufstellung und Beschreibung der insgesamt vorhandenen Kollektionsmethoden finden Sie in der PL/SQL-Dokumentation PL/SQL User's Guide and Reference. Gehen Sie dort in das Kapitel Using Collection Methods bzw. den dortigen Abschnitt Collection and Records. Neue Member-Funktion hinzufgen Keine Probleme mit eventuell verschachtelten Abhngigkeiten der einzelnen Objekte erhalten Sie, wenn es lediglich darum geht, die vorhandenen MemberFunktionen zu erweitern oder zu bearbeiten. Wir wollen unser Beispiel noch ein wenig erweitern, und eine weitere Funktion hinzufgen, mit der Sie die Summe der in der Buchliste gespeicherten Werte ermitteln knnen. Im Listing 2.45 finden Sie die Erweiterung des Objekts und im Listing 2.46 wird die Programmierung der neuen Methode gezeigt.
alter type mensch replace as object ( name varchar2(30), vname varchar2(30), strasse varchar2(30), plz varchar2(5), ort varchar2(30), geschl varchar2(1), gebdat date,

180

Datenbankobjekte in einer Oracle-DB

buecher buchliste, member function g_alter return number, pragma restrict_references(g_alter, wnds, wnps), member function g_anschrift return varchar2, pragma restrict_references(g_anschrift, wnds, wnps), member function g_buchzahl return number, pragma restrict_references(g_buchzahl, wnds, wnps), member function g_werte return number, pragma restrict_references(g_werte, wnds, wnps) ); / commit;
Listing 2.45: Erweitern des Objekts um eine neue Member-Funktion

create or replace type body mensch is member function g_alter return number is begin return floor(months_between(sysdate, gebdat) / 12) ; end; member function g_anschrift return varchar2 is anschrift varchar2(2000) := ' '; begin if geschl = 'M' then anschrift := 'Herrn' || chr(10) || chr(13); else anschrift := 'Frau' || chr(10) || chr(13); end if; anschrift := anschrift || vname || ' ' || name || chr(10) || chr(13); anschrift := anschrift || strasse || chr(10) || chr(13); anschrift := anschrift || plz || ' ' || ort; return anschrift; end; member function g_buchzahl return number is begin return buecher.count; end; member function g_werte return number is

Beschreibung der Objekte

181

i total

integer; number := 0;

begin for i in 1..buecher.count loop total := total + buecher(i).wert; end loop; return total; end; end; / show errors; commit;
Listing 2.46: Erstellen der neuen Member-Funktion g_werte

Innerhalb der neuen Funktion g_werte werden mit Hilfe einer Schleife alle vorhanden Elemente der Bcherliste durchlaufen und dabei werden die gespeicherten Werte mit Hilfe der Variablen total summiert. Der Wert dieser Variablen wird am Ende der Funktion als Ergebnis zurckgegeben. Wie Sie dem Beispiel weiterhin entnehmen knnen, erfolgt der Zugriff auf ein einzelnes Element der Bcherliste genau wie bei einem Datenfeld mit Hilfe eines Index. Danach erfolgt getrennt durch einen Punkt die Nennung der gewnschten Eigenschaft, d.h. die beiden folgenden Ausdrcke
buecher(2).wert := 22; x := buecher(2).wert;

ndern die Eigenschaft wert des zweiten Buchelements bzw. kopieren den aktuellen Inhalt in eine gewhnliche Variable. Schauen Sie sich das Ergebnis doch einfach mal an, indem Sie die nun folgende Abfrage eingeben:
SQLWKS> select name, gebdat, p.g_alter() as a, 2> p.g_buchzahl() as b, p.g_werte() as w 3> from menschen p 4> NAME GEBDAT -------------------------- ------------------Raymans 03-DEC-64 Raymans 27-DEC-65 Zschoge 13-JUL-62 Heger 12-MAY-69 4 rows selected.

A ----------35 34 38 31

B W -----------0 0 1 20 2 43 3 32.25

182

Datenbankobjekte in einer Oracle-DB

Varianten Ich mchte noch mal auf das Laden der Buchtabelle zurckkommen. In unserem Beispiel haben wir die Buchliste mit Hilfe individueller nderungsabfragen erstellt, was in der Praxis natrlich nicht denkbar wre, es sei denn, die zu ladende Tabelle besitzt wirklich nur eine Handvoll Datenstze. In Wirklichkeit stnden Sie jetzt vor der Herausforderung, eine wahrscheinlich als gewhnliche Tabelle vorliegende Bcherliste in das Kollektionsobjekt zu bertragen, was mit Hilfe von PL/SQL-Sprachelementen eigentlich auch kein greres Problem darstellt. Doch bevor wir uns eine Lsungsmglichkeit fr die eben beschriebene Aufgabe anschauen, erstellen wir zuerst einmal die relationale Hilfstabelle mit den gespeicherten Bchern (vgl. Listing 2.36).
drop table h_buch; / create table h_buch ( name varchar2(30), vname varchar2(30), lfdnr number, titel varchar2(50), wert number ) tablespace usr; commit; / insert into h_buch values insert into h_buch values insert into h_buch values insert into h_buch values insert into h_buch values insert into h_buch values commit;

('Raymans','Irina', 1, 'Oracle Workshop', 20); ('Zschoge', 'Helgo', 1, 'dBASE fr Fortgeschrittene', 20); ('Zschoge', 'Helgo', 2, 'Meine Rezepte', 23); ('Heger', 'Sascha', 1, 'Donald Duck', 5); ('Heger', 'Sascha', 2, 'Herr der Ringe', 9.30); ('Heger', 'Sascha', 3, 'Elementarteilchen', 17.95);

Listing 2.47: Erstellen und Fllen der Hilfstabelle zum automatischen Erzeugen der Buchlisten

Zum Laden dieser Buchliste erstellen wir die Funktion make_buchliste (vgl. Listing 2.48). Diese Funktion erhlt zur Identifizierung den Namen und Vornamen des Menschen, fr den es die vorhandenen Bcher aus unserer Hilfstabelle auslesen und die Bcherliste erstellen soll.
create or replace function make_buchliste(name in varchar2, vname in varchar2) return buchliste is x_buchl buchliste; begin declare cursor sel_buecher(s_name varchar2, s_vname varchar2) is select lfdnr, titel, wert from h_buch

Beschreibung der Objekte

183

where name = s_name and vname = s_vname order by lfdnr; b_lfdnr integer; b_titel varchar2(50); b_wert number; begin x_buchl := buchliste(); open sel_buecher(name, vname); loop fetch sel_buecher into b_lfdnr, b_titel, b_wert; Exit when sel_buecher%notfound; x_buchl.extend; x_buchl(x_buchl.count) := buch(b_lfdnr, b_titel, b_wert); end loop; close sel_buecher; return x_buchl; end; end; / show errors; commit;
Listing 2.48: Funktion zum Konstruieren eines Objekts aus einer Tabelle

Die Funktion enthlt eine Reihe bisher noch nicht bekannter Befehle, weshalb ich im Folgenden auf einzelne Passagen des Programms nher eingehen mchte. Zunchst einmal finden Sie am Anfang der Funktion verschiedene Deklarationen. Dabei wird neben drei gewhnlichen Variablen auch ein sogenannter Cursor definiert.
cursor sel_buecher(s_name varchar2, s_vname varchar2) is select lfdnr, titel, wert from h_buch where name = s_name and vname = s_vname order by lfdnr;

Mehr Informationen zu einem solchen Cursor und zustzliche Beispiele zu deren Verwendung finden Sie noch reichlich im weiteren Verlauf dieses Buches. An dieser Stelle sollen folgende Hinweise gengen: Der Cursor ermglicht uns innerhalb der Funktion die spezifizierte SQL-Abfrage auszufhren. In unserem Fall handelt es sich dabei um eine parametrisierte Abfrage, d.h. zur Laufzeit werden die beiden Parameter s_name und v_name innerhalb der where-Bedingung mit ihren konkreten

184

Datenbankobjekte in einer Oracle-DB

Werten bercksichtigt. Auerdem erhlt jeder Cursor einen Namen, mit dem er im weiteren Verlauf des Programms angesprochen werden kann. Damit die im Cursor definierte Abfrage ausgefhrt wird, muss dieser zunchst geffnet werden. Anschlieend haben Sie die Mglichkeit, die abgefragten Daten innerhalb einer Schleife der Reihe nach (sequentiell) abzurufen. Nach dem Lesen des letzten Satzes liefert der Cursor einen entsprechend Status, durch den die Schleife beendet bzw. verlassen werden kann und sptestens am Ende Ihres Programms sollten Sie die geffneten Cursor wieder schlieen. Der nun folgende Auszug des Programms zeigt die hierzu bentigten Befehle.
open sel_buecher(name, vname); loop fetch sel_buecher into b_lfdnr, b_titel, b_wert; Exit when sel_buecher%notfound; end loop; close sel_buecher;

Innerhalb der Schleife rufen Sie die vom Cursor gelieferten Datenstze mit Hilfe der fetch-Anweisung ab und speichern die in der zugehrigen Abfrage spezifizierten Spalten in die hierfr angelegten Variablen b_lfdnr, b_titel und b_wert. Was nun folgt, ist die berfhrung dieser Werte in ein Buchobjekt, und letztendlich muss dieses Buchobjekt an die aktuelle Bcherliste angehngt werden.
x_buchl.extend; x_buchl(x_buchl.count) := buch(b_lfdnr, b_titel, b_wert);

Die Bcherliste wird innerhalb der Funktion ber die Variable x_buchl gefhrt bzw. am Ende der Funktion zurckgegeben. Damit in die aktuelle Liste ein neues Buch passt, wird sie zuerst mit Hilfe der Methode extend erweitert. Ohne spezielle Parameter erweitert diese Methode die Liste um genau ein Element und wie Sie aus dem ersten Teil des Satzes folgerichtig schlieen knnen, bietet die extend-Methode verschiedene Varianten, mehrere Elemente auf einmal anzulegen oder sogar zu kopieren. Die Methode count haben Sie schon kennen gelernt. Sie liefert immer die aktuelle Zahl der in der liste enthaltenen Elemente, d.h. die Verwendung von
x_buchl(x_buchl.count)

verschafft Ihnen Zugriff auf das letzte Element der Buchliste. Der rechts vom Gleichheitszeichen stehende Ausdruck konstruiert dabei mit Hilfe der drei gelesenen Variablen ein Buchobjekt, so dass im Ergebnis dem neuen Element der Liste ein Buch zugewiesen wird. Beachten Sie allerdings noch die folgende notwendige Anweisung, damit das hier beschriebene Programm funktioniert.
x_buchl := buchliste();

Beschreibung der Objekte

185

Wie Sie schon wissen, liefert der Ausdruck buchliste() eine leere Bchersammlung und ist damit in der Lage entsprechende Variablen zu initialisieren. Ohne diese Initialisierung wrden Sie bei der Programmausfhrung eine Fehlermeldung erhalten, da die impliziten Methoden wie count oder extend nur bei initialisierten Listen funktionieren. Sofern Sie kein groer Fan von geschachtelten Ausdrcken sind, so knnen Sie die Zuweisung des Buches in die Buchliste auch anders programmieren. Statt der Verwendung des buch-Konstruktors
x_buchl(x_buchl.count) := buch(b_lfdnr, b_titel, b_wert);

knnen Sie ber die Bcherliste auch direkt auf ein einzelnes Buchobjekt zugreifen und dessen Eigenschaften damit direkt auslesen bzw. verndern.
x_buchl(x_buchl.count).lfdnr := b_lfdnr; x_buchl(x_buchl.count).titel := b_titel x_buchl(x_buchl.count).wert := b_wert

Das war auch schon alles. Was (vom Tag) noch brig bleibt ist die neue Funktion noch schnell auszuprobieren. Erstellen Sie hierzu noch einmal die Hilfstabelle h_mensch, in die Sie alle vorhandenen Daten kopieren. Lschen Sie danach die Tabelle menschen, so dass die nachfolgende SQL-Anweisung die Tabelle zusammen mit den Bcherlisten aufldt.
insert into menschen select name, vname, strasse, plz, ort, geschl, gebdat, make_buchliste(name, vname) from h_mensch; commit
Listing 2.49: Aufladen der Tabelle menschen zusammen mit den Bcherlisten

2.2.17 Tabelle (Tables)


Jetzt sprechen wir ber Tabellen, dem sicherlich zentralsten und wichtigsten Element der Schema-Objekte, denn ohne Tabellen ist die Speicherung irgendwelcher Daten in der Datenbank nicht mglich. Die Anlage neuer Tabelle erfolgt mit Hilfe der Anweisung create table. Daneben existieren die Befehle alter table und drop table, um vorhandene Definitionen zu bearbeiten bzw. zu lschen. Vereinfachend betrachtet, enthlt der Befehl create table neben dem Namen der neuen Tabelle im Wesentlichen nur noch die Definition der anzulegenden Spalten, den zu verwendenen Tablespace und bei Bedarf auch eine Regel, wie die zum Speichern notwendigen Ausdehnungen des Segments angelegt werden sollen.
create table <Name der Tabelle> ( <Definition der Spalten...> ) <Tablespace-Klausel> <Storage-Klausel>;

186

Datenbankobjekte in einer Oracle-DB

Dabei knnen Sie die Storage-Klausel weglassen, wenn die Tabelle die im Tablespace verankerten Standardwerte verwenden soll. Die Vorgabe eines speziellen Tablespace kann ebenfalls entfallen. In dem Fall verwendet Oracle entweder den dem Benutzer zugeordneten Standardwert oder den Tablespace system. Speicherbelegung Im Folgenden mchte ich einmal etwas genauer auf die Speicherbelegung des zu einer Tabelle gehrenden Segments eingehen. Wie schon gesagt, knnen Sie mit Hilfe der Storage-Klausel festlegen, wie und wie viele Segmentbereiche (vgl. Abb. 1.5) zum Speichern der Tabellendaten angelegt werden. Den letzten Teil des vorhergehenden Satzes knnte man auch allgemeiner formulieren, denn er gilt nicht nur fr Tabellen, sondern berall da, wo Sie eine storage-Klausel angeben knnen (z.B. Indices, Snapshots und Rollback-Segmente). Die einzelnen Ausprgungen dieser Klausel werden dabei hinter dem Wrtchen storage in Klammern spezifziert.
storage (initial .. next .. minextents .. maxextents .. pctincrease ..)

Hinter den verschiedenen Schlsselwrtern mssen Sie die jeweils bentigten Werte vorgeben. Ansonsten ist neben der Bedeutung der einzelnen Ausprgungen eigentlich nur noch wichtig, dass Sie deren Reihenfolge zum einen wahlfrei und zum anderen auch einzeln bzw. in beliebiger Kombination verwenden knnen. Die genaue Bedeutung der einzelnen storage-Parameter knnen Sie der Tabelle 2.4 entnehmen.
Storage-Klausel initial next minextents Bedeutung Legen Sie hier bei Bedarf die Gre des ersten Segmentbereichs in Kilo(K) oder Megabyte (M) fest. Mit diesem Parameter knnen Sie die Gre der weiteren Segmentbereiche (Extents) in Kilo- (K) oder Megabyte (M) festlegen. Hier knnen Sie die Anzahl der Extents festlegen, die beim Anlegen der Tabelle bzw. des Objekts erzeugt werden. Standardmig legt Oracle immer ein Extent an, denn ohne einen einzigen Segmentbereich ist das Objekt gar nicht vorhanden. Geben Sie mit diesem Parameter die maximale Anzahl der zustzlichen Segmentbereiche vor oder verwenden Sie statt einer Zahl das Wrtchen unlimited, damit die Tabelle bzw. das Objekt uneingeschrnkt wachsen kann. Die hier vorgegebene Zahl wird als Prozentwert interpretiert, um die jeder neue Extent vergrert wird. Der Standardwert hierfr betrgt 50%. Sollen die neuen Segmente nicht automatisch vergrert werden, dann mssen Sie pctincrease zusammen mit dem Wert 0 verwenden.

maxextents

pctincrease

Tabelle 2.4: Beschreibung der storage-Klausel

Einen guten berblick ber alle mglichen Varianten erhalten Sie im brigen auch wieder mit Hilfe des Schema-Managers bzw. DBA Studios, in dem Sie dort beispielsweise verschiedene Optionen bzw. deren Kombination auswhlen und anschlieend die von dem Programm generierte SQL-Anweisung betrachten (vgl. Abb. 2.14).

Beschreibung der Objekte

187

Abbildung 2.14: Generieren einer storage-Klausel mit Hilfe des Schema-Managers

Zwei weitere Klauseln, die Sie bei der Anlage einer Tabelle oder auch anderer datenspeichernder Objekte verwenden knnen, heien pctfree bzw. pctused. Mit pctfree reservieren Sie in jedem Extent des Segments eine Art Platzreserve in Prozent, die dem Wachstum durch nderungen von bestehenden Datenstzen vorbehalten ist. Standardmig verwendet Oracle fr diesen Wert 10%, d.h. nach dem vollstndigen Auffllen des Extents sind immer noch 10% des Platzes frei, der anschlieend fr nderungen der in dem Segmentbereich gespeicherten Daten verwendet wird. Mit der anderen pctused-Klausel legen Sie eine Art Schwellenwert (in Prozent) fest, der vorgibt, wie weit die Belegung eines einstmals vollen Segmentbereichs wieder sinken muss, bevor wieder neue Datenstze hineingeschrieben werden. Der Standardwert fr diesen Parameter liegt bei 40 Prozent. Die pctused-Klausel verhindert somit, dass der Status eines Extents permanent zwischen voll und leer wechselt, denn entsprechend dem Standardwert beginnt Oracle erst wieder damit neue Datenstze in den Extent zu schreiben, wenn seine Belegung unter 40% sinkt. Danach wird er allerdings wieder so lange mit neuen Datenstzen gefllt, bis der in pctfree festgelegte Wert erneut erreicht wird. Unterlegen wir das Ganze mal mit Hilfe eines kleinen Beispiels. Legen Sie hierzu die Tabelle lohnarten mit Hilfe des folgenden Skripts (vgl. Listing 2.50) an.

188

Datenbankobjekte in einer Oracle-DB

drop table lohnarten; create table lohnarten (la varchar2(3)) tablespace usr storage (initial 4k next 10k minextents 4 pctincrease 0); commit;
Listing 2.50: Anlage der Tabelle lohnarten mit spezieller Speicherbelegungsregel

Mit Hilfe einer Abfrage auf die View dba_segments knnen Sie die definierte Speicherbelegung einer jeden Tabelle bzw. eines jeden Segments abfragen (vgl. Listing 2.51). Bei einer solchen Abfrage knnen Sie je nach Bedarf den Namen des Eigentmers, den Tablespace oder den Namen des Segments, das ist beispielsweise der Name der Tabelle oder des Index oder den Segmenttyp (z.B. TABLE oder INDEX) als einschrnkende Kriterien verwenden.
SQLWKS> select bytes, blocks, extents, initial_extent, next_extent, 2> min_extents, max_extents, pct_increase 3> from dba_segments where segment_name = 'LOHNARTEN'; BYTES BLOCKS EXTENTS INITIAL NEXT_ MIN_ MAX__INCREA ----- ------- ------- ----------- ---------- -------- -------- -------34816 17 4 4096 10240 4 121 1 1 row selected.
Listing 2.51: Analyse des Segments lohnarten mit Hilfe der View dba_segments

In unserem Beispiel betrgt die Gre des ersten Extents also 4096 Byte (4k). Entsprechend der Konfiguration der Datenbankinstanz (db_block_size = 2048) war die Blockgre auf 2048 Bytes eingestellt, also entspricht die Gre des ersten Extents genau Blcken. Sofern Sie die Speicherbelegung einmal nachrechnen mchten, dann sollten Sie Ihre vorgegebenen Werte zunchst immer in Blcken umrechnen, ggf. aufrunden (es gibt keine halben Blcke) und die erhaltene Blockzahl danach wieder mit der konfigurierten Blockgre multiplizieren. Mit der Anlage der Tabelle wurden aufgrund unserer storage-Klausel drei weitere Extents angelegt. Fr den Parameter pctincrease hatten wir den Wert 0 vergeben, so dass alle Segmenterweiterungen die gleiche Gre besitzen. Jedes dieser weiteren Extents wird mit einer Gre von jeweils 10k angelegt bzw. je 5 Blcken angelegt. Somit belegt das ganze Segment bzw. die Tabelle insgesamt 17 Blcke, was zusammen die Summe von 34816 Byte ergibt. Wie bei den meisten anderen Dingen, so ist auch hierbei die Entscheidung ber viel oder wenig letztendlich Ansichtssache. Dennoch, so finde ich, sind 34k fr eine leere Tabelle ganz schn viel Platz. Sie knnen die Erweiterungen (Extents) einer Tabelle auch mit Hilfe einer Abfrage auf die Tabelle dba_extents (vgl. Listing 2.52) untersuchen. Der wesentliche Unterschied zu der vorhin gezeigten Abfrage ist, dass hierbei jeder Bereich des Segments einzeln angezeigt wird.

Beschreibung der Objekte

189

SQLWKS> select extent_id, bytes, blocks 2> from dba_extents 3> where segment_name = 'LOHNARTEN'; EXTENT_ID BYTES BLOCKS ---------- ---------- ---------0 4096 2 1 10240 5 2 10240 5 3 10240 5 4 rows selected.
Listing 2.52: Analyse des Segments lohnarten mit Hilfe der View dba_extents

Wie leer eine Tabelle bzw. das zugehrige Segment wirklich ist, knnen Sie im Nachhinein brigens mit Hilfe des Pakets dbms_space feststellen, denn dort ist die Prozedur unused_space enthalten, mit der Sie den freien Platz in einem Segment ermitteln knnen (vgl. Listing 2.53). Diese Paketprozedur erhlt als Eingabeparameter im Wesentlichen den Namen des zu untersuchenden Segments und liefert die Belegungsdaten in Form verschiedener Ausgabeparameter zurck. Fr uns bedeutet das, dass wir die Prozedur innerhalb eines PL/SQL-Skripts verwenden mssen, in dem wir die Ausgabeparameter als Variable definieren und nach dem Aufruf der Prozedur fr deren Anzeige am Bildschirm sorgen.
set serveroutput on; declare total_blocks number; total_bytes number; unused_blocks number; unused_bytes number; last_used_fid number; last_used_id number; last_used_block number; begin dbms_space.unused_space('SYSTEM', 'LOHNARTEN','TABLE', total_blocks, total_bytes, unused_blocks, unused_bytes, last_used_fid, last_used_id, last_used_block); dbms_output.put_line('total_blocks to_char(total_blocks)); dbms_output.put_line('total_bytes to_char(total_bytes)); dbms_output.put_line('unused_blocks to_char(unused_blocks)); dbms_output.put_line('unused_bytes to_char(unused_bytes)); dbms_output.put_line('last_used_extend_file_id to_char(last_used_fid)); : ' || : ' || : ' || : ' || : ' ||

190

Datenbankobjekte in einer Oracle-DB

dbms_output.put_line('last_used_extend_block_id: ' || to_char(last_used_id)); dbms_output.put_line('last_used_block : ' || to_char(last_used_block)); end;


Listing 2.53: Verwenden von dbms_space.unused_space in einem Skript

In dem Skript werden verschiedene Variablen fr die im Paket dbms_space vorhandene Prozedur unused_space deklariert und anschlieend wird die Prozedur aufgerufen. Die Ausgabe der einzelnen Ergebnisse erfolgt danach mit Hilfe der Prozedur put_line aus dem Paket dbms_output. Diese Prozedur wird uns im weiteren Verlauf des Buches noch hufiger begegnen. Mit ihr knnen Sie innerhalb von PL/SQLProgrammen Meldungen sammeln und am Ende der Prozedur am Bildschirm ausgeben. Oftmals wird sie auch verwendet, um mit ihrer Hilfe in einer Prozedur eine Ablaufverfolgung durchzufhren.
dbms_output.put_line('irgendein Text')

Mit Hilfe der Prozedur knnen Sie eine beliebige Zeichenfolge, die innerhalb der Klammern vorgegeben wird, in einen speziellen Ausgabepuffer kopieren. Dieser Ausgabepuffer wird am Ende der Prozedur oder des Skripts am Bildschirm ausgegeben, wobei Letzteres nur dann passiert, wenn Sie die Serverausgabe eingeschaltet haben.
set serveroutput on;

Diese Serverausgabe knnen Sie mit einem speziellen set-Kommando einschalten, so dass am Ende unseres Skripts folgende Informationen am Bildschirm erscheinen:
total_blocks : total_bytes : unused_blocks : unused_bytes : last_used_extend_file_id : last_used_extend_block_id: last_used_block : 17 34816 16 32768 3 12 1

In unserem Beispiel sind in dem Segment lohnarten zur Zeit also ber 30k frei. Wenn Sie die wieder freigeben wollen, dann mssen Sie sich in unserem Fall zunchst einmal von der minextents-Klausel trennen, denn die wrde aufgrund ihrer aktuellen Einstellung jegliche Freigabeaktivitten verhindern.
alter table lohnarten storage (minextents 1); commit;

Beschreibung der Objekte

191

Die nderung der Speicherbelegungsregel erfolgt mit Hilfe einer alter-Anweisung und da es sich in unserem Beispiel um eine Tabelle handelt, heit der vollstndige Befehle entsprechend alter table. Anschlieend erfolgt die Vorgabe einer neuen storage-Klausel, wobei es hierbei ausreicht, nur die zu ndernden Parameter der Klausel vorzugeben. Beachten Sie hierbei allerdings, dass Sie gerade nur die Regel zur Speicherbelegung verndert haben, d.h. in der Datenbank ist in Bezug auf das Segment sonst noch gar nichts passiert. In der Praxis wird die storage-Klausel fr existierende Objekte hufig zusammen mit den Parametern pctincrease und maxextents verwendet, um im laufenden Betrieb die Vergrerung neuer Erweiterungen (Extents) zu verndern bzw. die zulssige Anzahl dieser Erweiterungen zu vergrern. Im nchsten Schritt geben wir den nicht mehr bentigten Speicherplatz wieder frei. Hierzu verwenden wir wiederum die Anweisung alter table zusammen mit der Klausel dellocate unused.
alter table lohnarten deallocate unused keep 7k; commit;

In unserem Beispiel spezifizieren wir zustzlich die optionale Erweiterung keep 7k, die dazu fhrt, dass Oracle nicht den gesamten freien Speicher freigibt, sondern mindestens 7k bleiben fr das gesamte Segment reserviert. Wenn Sie nach Ausfhrung dieser Anweisungen das Segment noch einmal mit Hilfe der vorgestellten Methoden analysieren, dann werden Sie feststellen, dass Oracle die Extents mit der Id 2 und 3 gelscht hat. Die Ausdehnung mit der Id 1 konnte aufgrund unserer keep-Vorgabe nicht gelscht werden, allerdings wurde es entsprechend gekrzt. Ohne die keep-Klausel wre auch dieser erste Zusatzextent aus der Datenbank gelscht worden.
SQLWKS> select extent_id, bytes, blocks 2> from dba_extents 3> where segment_name = 'LOHNARTEN'; EXTENT_ID BYTES BLOCKS ---------- ---------- ---------0 4096 2 1 6144 3 2 rows selected. total_blocks : total_bytes : unused_blocks : unused_bytes : last_used_extend_file_id : last_used_extend_block_id: last_used_block : 5 10240 4 8192 3 12 1

192

Datenbankobjekte in einer Oracle-DB

Anhand des Beispiels der Tabellen bin ich nun einmal etwas ausfhrlicher auf die Speicherbelegung der Segmente eingegangen. Wie schon mehrfach angedeutet, gilt das hier Gesagte allerdings nicht nur fr Tabellen, sondern eben fr alle mit Hilfe von Segmenten gespeicherten Daten, d.h. die hier beschriebenen Mglichkeiten sind auch bei den Indices, Rollback-Segmenten oder Snapshots verfgbar. Beispiele Die einfachste Form des Befehls create table besteht also aus einem Tabellennamen, einer oder mehreren Spaltendefinitionen und dem Ort bzw. der Regel zur Speicherbelegung. Hierzu haben Sie im bisherigen Verlauf dieses Workshops schon mehrfach Beispiele gesehen. Als Erstes legen wir noch einmal die Lohnartentabelle (vgl. Listing 2.54) an, und sorgen anschlieend auch sofort mit Hilfe einzelner insertAnweisungen fr ein paar Daten in dieser Tabelle.
drop table lohnarten; create table lohnarten( la varchar2(3), la_text varchar2(50) ) tablespace usr storage(initial 4k minextents 1); insert into insert into insert into insert into insert into commit; lohnarten lohnarten lohnarten lohnarten lohnarten values values values values values ('100','Grundgehalt'); ('110','bertraifliche Zulage'); ('120','Sonstige Zulage'); ('200','berstunden'); ('300','Urlaubsgeld');

Listing 2.54: Anlegen der Tabelle lohnarten

Bei vielen Standardprodukten entspricht die Anlage von Tabellen genau dieser Struktur. Das ist vor allem dann der Fall, wenn die zum Arbeiten bentigten Tabellen mit Hilfe der Standardsoftware angepasst und erzeugt werden knnen. Der Grund dafr ist auch einleuchtend, denn, wie hier beschrieben, knnen in nahezu allen relationalen Datenbanken Tabellen angelegt werden, wenn man mal von der Vorgabe des Tablespaces und der storage-Klausel absieht. Oracle bietet allerdings noch eine Reihe weiterer Mglichkeiten, schon mit der Tabellendefinition auch Indices oder bestimmte Regelwerke an- bzw. festzulegen. Wie man explizit Indices anlegen kann, das haben Sie bei der Behandlung des entsprechenden Schema-Objekts schon gesehen. Im nchsten Schritt geht es darum, im Rahmen der Tabellendefinition implizite Indices anzulegen. Bei solchen Optionen, gleichgltig ob Indices, Regeln oder Abhngigkeiten spricht man blicherweise von sogenannten Constraints (Zwnge). Sie werden entweder im Rahmen der Tabellendefinition oder nachtrglich mit Hilfe einer alter tableAnweisung definiert. Die Varianten, Verfgbarkeit und Anwendung der verschiedenen Constraints ist in den unterschiedlichen Datenbanksystemen, im Unterschied zur eigentlichen create table-Anweisung sehr verschieden.

Beschreibung der Objekte

193

Generell folgt hinter den Schlsselwrtern create table der Name der Tabelle und danach folgt in Klammern eine Aufzhlung der bentigten Spalten. Die einzelnen Spaltendefinitionen werden dabei durch Komma getrennt. Jede einzelne Spaltendefinition besteht wiederum aus dem Spaltennamen, dem der bentigte Datentyp folgt. Danach folgen zwei weitere optionale Parameter. Zum einen knnen Sie festlegen, ob eine Spalte berhaupt mit einem Wert gefllt werden muss oder ob sie auch leer (null) bleiben darf, wobei Letzteres dem Standardwert von Oracle entspricht. Zum anderen knnen Sie die Spalte einen Standardwert definieren. Damit ergibt sich insgesamt folgendes Schema zur Definition jeder einzelnen Spalte in einer Tabelle:
<Spaltenname> <Datentyp> [default <Standardwert>] [null|not null]

Die am meisten verwendeten Datentypen sind sicherlich varchar2 fr das Speichern variabel langer Zeichenfolgen, date zum Speichern von Datums- und/oder Zeitwerten und number ggf. mit Vorgabe der mglichen Vor- bzw. Nachkommastellen (number(v,n)).
zeichenspalte varchar2(10), nummer number, nummermitlaenge number(7,2), datum date

Als Standardwert drfen Sie im Rahmen der Spaltendefinition einen beliebigen gltigen Ausdruck verwenden. Der darf allerdings keinen Bezug auf andere Spalten der Tabelle bzw. verschiedene vom System vorgehaltene Systemspalten (z.B. rownum) enthalten und muss in Bezug auf den Datentyp und Lnge zur zugehrigen Spalte passen. Meistens werden als Standardwerte irgendwelche Konstanten (z.B. 100 oder 43) bzw. die Variable sysdate zum Einmelden des Systemdatums verwendet. Beachten Sie allerdings, dass die Verwendung des Standardwerts beim Einfgen neuer Datenstze nur dann greift, wenn Sie das zugehrige Feld in der insert-Anweisung nicht spezifizieren.
zeichenspalte varchar2(10) default 'XXL', nummer number default 5*2-2, nummermitlaenge number(7,2) default (33.2), datum date default sysdate

Wenn Sie eine Spalte zusammen mit der Regel not null anlegen, dann mssen Sie ihr beim Einfgen eines Datensatzes oder beim ndern immer einen konkreten Wert zuweisen. Zeichenfolgen mssen in dem Fall beispielsweise mindestens ein Leerzeichen, numerische Felder mindestens die Zahl 0 und Datumsfelder irgendein gltiges Datum enthalten.
zeichenspalte varchar2(10) default 'XXL' not null, nummer number default 5*2-2 not null, nummermitlaenge number(7,2) default 33.2 not null, datum date default sysdate not null

194

Datenbankobjekte in einer Oracle-DB

Manche Datenbanksystem unterscheiden sich in Bezug auf die Vergabe eines Standardwertes zusammen mit der Option not null. Bei manchen Systemen schlieen sich diese beiden Option sogar gegeneinander aus, da schon die insert-Anweisung eine Verletzung der Klausel not null erkennt und die Vergabe des Standardwertes erst spter erfolgt. In Oracle ist das anders, d.h. werden beide Optionen zusammen verwendet, dann greift der Standardwert, wenn Sie die zugehrige Spalte beim insert-Befehl weglassen und auf der anderen Seite haben Sie nicht die Mglichkeit, die Spalte im Rahmen einer update-Anweisung auf null zu setzen. Indices Im folgenden Beispiel legen wir fr unsere Tabelle lohnarten im Nachhinein einen Primrschlssel mit Hilfe einer constraint-Klausel (vgl. Listing 2.55) an. Der Vorteil das mit Hilfe einer solchen Klausel anstelle eines gewhnlichen eindeutigen Indices zu tun ist, dass Oracle diese Definition bei anderen Aktivitten bercksichtigen und sein Verhalten dementsprechend optimieren kann.
alter table lohnarten drop constraint lohnarten_pk; commit; alter table lohnarten add constraint lohnarten_pk primary key (la) using index tablespace indx storage(initial 2k next 4k) ; commit;
Listing 2.55: Lschen und Anlegen eines Primrschlssels

Mit dem Beispiel schlagen wir gleich zwei Fliegen mit einer Klappe. Das nachtrgliche Lschen oder Anlegen von Constraints erfolgt immer mit Hilfe des Befehls alter table zusammen mit der Klausel drop constraint bzw. add constraint, je nachdem, ob Sie eine vorhandene Regel lschen oder eine neue Regel anlegen wollen. Auerdem besitzen die verschiedenen Constraints einen bei der Anlage festgelegten Namen, mit dessen Hilfe sie beispielsweise wieder gelscht werden knnen. Die Schlsselwrter using index sind optional und leiten bei deren Verwendung die Spezifizierung von Speichervorgaben fr das zugehrige Indexsegment ein. Hier knnen Sie also den Tablespace vorgeben oder mit Hilfe der storage-Klausel die Speicherbelegung fr den Index vorgeben. In unserem Beispiel (Listing 2.55) lschen wir zunchst das Constraint mit dem Namen lohnarten_pk. Anschlieend legen wir es erneut an, wobei wir den Typ primary key zur Anlage eines Primrschlssels verwenden. Hierbei mssen Sie im Anschluss alle zum Primrschlssel gehrenden Felder in Klammern aufzhlen. Das hier durchgefhrte Szenario, erst drop dann add, entspricht brigens der blichen Vorgehensweise beim ndern, da es eine Anweisung der Art change constraint nicht gibt.

Beschreibung der Objekte

195

Natrlich htten wir den Primrschlssel der Tabelle lohnarten auch gleich bei deren Anlage definieren knnen, wobei wir die zugehrigen Anweisungen in dem Fall folgendermaen erweitern mssen:
create table lohnarten( la varchar2(3), la_text varchar2(50), constraint lohnarten_pk primary key (la) using index tablespace indx storage(initial 2k next 4k) ); tablespace usr storage(initial 4k minextents 1);

Wie Sie an dem Beispiel sehen, werden Constraints, wenn Sie bei der Anlage von Tabellen spezifiziert werden, quasi wie zustzliche Extraspalten angelegt. Dabei ist es gleichgltig, ob Sie die Constraints am Anfang, zwischen den einzelnen Spalten oder ganz am Ende, d.h. nach der letzten Spaltendefinition angeben. Ich persnlich finde es bersichtlicher, wenn sie am Ende stehen, aber das ist wie so vieles im Leben sicherlich mal wieder Geschmacksache. Primrschlssel kann es, genau wie in dem entsprechenden Kinofilm, nur einen geben. Insgesamt knnen eindeutige Felder oder Feldkombinationen natrlich mehrfach auftreten und anstelle zustzlicher expliziter eindeutiger Indices knnen Sie auch beliebige weitere unique-Constraints definieren, was eigentlich fast genauso wie die Anlage des Primrschlssels funktioniert:
constraint <name> unique (<Felder>) using index ...

berwachung von Spalten Im Rahmen der Spaltendefinition haben Sie mit der null bzw. not null Option schon eine Art Miniberwachung der Spaltenwerte kennen gelernt. Hier geht es jetzt um die Erstellung sogenannter Check-Constraints, mit deren Hilfe sich komplexere Prfungen fr einzelne oder eine Kombination von Spalten definieren lassen. Als Demonstrationsobjekt soll hierzu eine weitere Tabelle bezuege (vgl. Listing 2.56) erstellt werden, in der spter die einzelnen Gehaltsbestandteile jedes Mitarbeiters gespeichert werden knnen. Bei der Definition der Tabelle werden wir auch gleich einige Regeln zur berwachung der enthaltenen Spalten anlegen.
drop table bezuege; create table bezuege( persnr varchar2(10) la varchar2(3) stunden number(5,2) default tage number(5,2) default lohnsatz number(5,2) default betrag number(9,2) default

0 0 0 0

not not not not not not

null, null, null, null, null, null,

196

Datenbankobjekte in einer Oracle-DB

constraint bezuege_pk primary key (persnr, la), constraint check_lohnsatz check (lohnsatz >= 0), constraint check_record check (betrag<>0 and (tage=0 and stunden=0) or betrag=0 and (tage<>0 or stunden<>0)) ) tablespace usr; commit;
Listing 2.56: Anlage der Tabelle bezuege mit verschiedenen Feldprfungen

In unserem Beispiel kann ein Gehaltsbestandteil neben einem Lohnsatz immer aus der Vorgabe eines Betrags oder einer Kombination aus Tagen und Stunden bestehen. Der Lohnsatz darf dabei nur positive Werte annehmen, was wir mit Hilfe der Regel check_lohnsatz festlegen. Die andere Regel heit check_record und berprft die Felder betrag, tage und stunden, so dass die oben beschriebene Eingaberegel beachtet wird. Die Verarbeitung eines check-Constraints entspricht im Prinzip einer wenn- bzw. ifBedingung, d.h. die zugehrige Regel gilt als erfllt, wenn der spezifizierte Ausdruck den Wahrheitswert wahr zurckliefert. Das Hinzufgen oder Lschen solcher Prfungen erfolgt natrlich wieder mit Hilfe der alter table-Anweisung entsprechend der bei den Indexen beschriebenen Verfahrensweise. Integrittsprfungen Wenn Sie noch unerfahren im Umgang mit relationalen Datenbanksystemen sind, dann stellen Sie sich beim Lesen der berschrift vielleicht die Frage, was hiermit gemeint sein knnte. Genau genommen geht es bei der berschrift um das Thema der sogenannten referenziellen Integritt. Ich habe mal wieder keine Kosten und Mhen gescheut und bin auf die Suche nach einer einfachen aber dennoch halbwegs zutreffenden Erklrung gegangen. Was ist referenzielle Integritt? Referenzielle Integritt ist ein Regelsystem, mithilfe dessen die Datenbank (Oracle) sicherstellt, dass Beziehungen zwischen Datenstzen in Detailtabellen gltig sind und dass verknpfte Daten nicht versehentlich gelscht oder gendert werden. Sofern Ihnen dieser Erklrungsversuch noch zu oberflchlich ist, dann wird das Ganze sicherlich klarer, wenn wir es im Rahmen eines Beispiels betrachten. Betrachten Sie hierzu noch einmal unsere beiden bisher angelegten Tabellen lohnarten und bezuege (vgl. Abb. 2.15).

Beschreibung der Objekte

197

bezuege lohnarten
persnr la tage stunden lohnsatz betrag la la_text

Fremdschlssel, der auf der lohnarten-Tabelle beruht.


Abbildung 2.15: Beziehungen verknpfter Tabellen

In unserem Beispiel werden die einzelnen Bezge mit Hilfe einer Lohnart gespeichert. Dabei soll sichergestellt werden, dass die verwendete Lohnart berhaupt gltig ist bzw. existiert. Das wre zwar sicherlich auch im Rahmen einer Prfung auf konstante Werte mglich, doch htte ein solches Verfahren den Nachteil, dass Sie mit jeder Lohnartenerweiterung die Tabellendefinition anpassen mssten. Auerdem wre fr den Endanwender nicht transparent, fr welche Lohnarten in der Tabelle eine Prfung stattfindet bzw. welche Lohnarten vielleicht versehentlich vergessen wurden. Komfortabler und auch flexibler wre da schon ein Verfahren, das diese Prfung mit Hilfe der Lohnartentabelle vornimmt, d.h. alle in der Lohnartentabelle definierten Schlssel drfen auch in der Tabelle bezuege vorkommen. In dem Fall verweist (referenziert) die Tabelle bezuege ber das Feld la auf die Lohnartentabelle und leiht sich bei dieser quasi deren Schlssel aus (Fremdschlssel), d.h. bei dem Lohnartenfeld (la) handelt es sich in der Tat um einen fremden Schlssel aus der Lohnartentabelle. Das Verfahren der referenziellen Integritt verlangt neben dieser noch recht einfachen Werteprfung mittels Referenztabelle jedoch auch noch eine Rckkopplung aus dieser Tabelle zu den jeweiligen Fremdschlsseln. Wird beispielsweise eine Lohnart gelscht, dann darf das nur mglich sein, wenn diese nirgendwo mehr als Fremdschlssel bentigt wird. Das Gleiche gilt natrlich auch, wenn eine Lohnart in der Referenztabelle gendert wird. Das zur Durchfhrung einer solchen Prfung verwendete Constraint heit sprechenderweise foreign key und wird prinzipiell wie die anderen bisher besprochenen Regeln verwendet (vgl. Listing 2.57).
drop table bezuege; create table bezuege( persnr varchar2(10) la varchar2(3)

not null, not null,

198

Datenbankobjekte in einer Oracle-DB

stunden number(5,2) tage number(5,2) lohnsatz number(5,2) betrag number(9,2)

default default default default

0 0 0 0

not not not not

null, null, null, null,

constraint bezuege_pk primary key (persnr, la), constraint check_lohnsatz check (lohnsatz >= 0), constraint check_record check (betrag<>0 and (tage=0 and stunden=0) or betrag=0 and (tage<>0 or stunden<>0)), constraint check_la foreign key (la) references lohnarten(la) ) tablespace usr; commit;
Listing 2.57: Anlegen der Tabelle zusammen mit Integritts-Constraints

Selbstverstndlich knnen Sie die Regel auch wieder im Nachhinein mit Hilfe einer alter table-Anweisung hinzufgen. In jedem Fall mssen Sie hinter den Schlsselwrtern foreign key die zu berwachenden Felder in Klammern vorgeben. Mit Hilfe des Schlsselworts references leiten Sie den Verweis auf die Prftabelle ein, indem Sie deren Namen dahinter vorgeben. Zum Schluss folgen dann in Klammern die entsprechenden Spaltennamen aus der Prftabelle. Damit ergibt sich das im Folgenden gezeigte Schema:
foreign key (feld1 [, feld2] ...) references <tabelle>(rfeld1 [, rfeld2] ...)

Beachten Sie weiterhin, dass die Referenzierung auf eine solche Prftabelle nur mglich ist, wenn dort fr die einzelnen Spalten ein Primrschlssel oder zumindest ein eindeutiger Index angelegt ist. Selbst ohne diesen Zwang wre die Anlage eines solchen Indexes naheliegend, damit der Zugriff auf die Prftabelle entsprechend schnell durchgefhrt werden kann. Genau genommen muss Oracle wegen des Indexes sogar gar keinen Zugriff auf die eigentliche Tabelle machen, denn schon mit der Existenz des Indexeintrags ist die berwachungsregel erfllt. Halten wir an dieser Stelle mal kurz inne und probieren das Ganze einfach mal aus, bevor wir unser Konstrukt im Rahmen des weiteren Verlaufes des Kapitels vielleicht wieder zerpflcken. So knnen Sie die beiden nachfolgenden Datenstze beispielsweise problemlos einfgen, da hierbei alle definierten Regeln erfllt werden.
insert into bezuege values ('4711','100',0,0,0,1000); insert into bezuege values ('4711','300',4,3.5,0,0);

Die drei nun folgenden Datenstze knnen sie nicht in die Datenbank einfgen, da hierbei immer eine der definierten check-Constraints verletzt wird.
insert into bezuege values ('4712','100',3,0,0,1000); insert into bezuege values ('4712','300',0,3.5,0,1); insert into bezuege values ('4712','300',0,0,-100,1);

Beschreibung der Objekte

199

Im ersten Fall werden die Felder Tage und Betrag und im zweiten Fall die Felder Stunden und Betrag gleichzeitig bestckt, was entsprechend der Regel check_record verboten ist. Mit dem letzten Datensatz wird versucht, einen negativen Lohnsatz zu speichern, was durch die Regel check_lohnsatz verhindert wird. Mit Hilfe der nchsten beiden Datenstze versuchen wir nun Datenstze mit einer ungltigen Lohnart einzufgen, was aufgrund der Regel check_la ebenfalls verhindert wird.
insert into bezuege values ('4712','101',0,0,0,1000); insert into bezuege values ('4712','301',4,2.5,0,0);

Als letzten Schritt greifen wir unser System nun noch von der Lohnartenseite her an, indem wir versuchen, eine verwendete Lohnart zu lschen bzw. umzuschlsseln.
delete lohnarten where la = '100'; update lohnarten set la = '301' where la = '300';

Beide nderungen werden aufgrund der Regel check_la verhindert. Die Lohnarten 100 und 300 sind in der Tabelle bezuege vorhanden und knnen deshalb in der Lohnartentabelle weder gelscht noch umgeschlsselt werden. Das Lschen oder ndern nicht verwendeter Lohnarten funktioniert dahingegen auch weiterhin einwandfrei, wie das nun folgende letzte Beispiel zeigt.
delete lohnarten where la = '110'; update lohnarten set la = '121' where la = '120';

Nachtrgliches Anlegen von Prfungen Wie ich schon angedeutet habe, knnen die soeben beschriebenen Constraints zur berprfung der in den Tabellen gespeicherten Daten auch im Nachhinein mit Hilfe einer entsprechenden alter table-Anweisung erstellt werden. Fr jede zu lschende Regel mssen Sie dabei eine drop- und fr jedes neue Constraint eine entsprechende add-Klausel verwenden (vgl. Listing 2.58).
alter table bezuege add constraint bezuege_pk primary key (persnr, la) add constraint check_lohnsatz check (lohnsatz >= 0) add constraint check_record check (betrag<>0 and (tage=0 and stunden=0) or betrag=0 and (tage<>0 or stunden<>0)) add constraint check_la foreign key (la) references lohnarten(la) ; commit;
Listing 2.58: Nachtrgliches Anlegen von Constraints

Beim nachtrglichen Anlegen solcher Prfregeln fhrt Oracle diese zunchst auf den gesamten Datenbestand aus und erst nach der erfolgreichen Durchfhrung aller Prfungen werden die neuen Constraints in der Tabelle installiert. Falls das strt, dann knnen Sie die Prfungen mit einer speziellen Klausel anlegen, so dass nur alle neuen oder genderten Datenstze geprft werden.

200

Datenbankobjekte in einer Oracle-DB

add constraint check_la foreign key (la) references lohnarten(la) enable novalidate

Diese besondere Klausel heit enable novalidate. Standardmig werden neue Constraints mit der Klausel enable validate angelegt, so dass die oben beschriebene Vorabprfung durchgefhrt wird. Neben diesen beiden Varianten existiert auch noch die Klausel disable, die zwar zur Anlage, jedoch nicht zur Aktivierung der Prfroutine fhrt.
add constraint check_la foreign key (la) references lohnarten(la) disable

Generell knnen Sie die Constraints im Nachhinein je nach Bedarf ein- oder ausschalten, was wieder mit Hilfe einer entsprechenden alter table-Anweisung mglich ist.
alter table bezuege enable validate constraint check_lohnsatz disable constraint check_record; commit;

Hinzufgen, ndern von Spalten Natrlich knnen auch vorhandene Tabellen nachtrglich in Ihrer Struktur verndert werden, jedoch haben Sie hierbei nur sehr eingeschrnkte Mglichkeiten:

: : : : :

Das ndern des Datentypes (z.b. von varchar2 in date) ist nur mglich, wenn die zugehrige Spalte in allen Datenstzen den Wert null enthlt. Das Gleiche gilt auch, wenn Sie die definierte Lnge verkrzen wollen. Das Verlngern eines Datenfeldes ist dagegen immer mglich. Ein eventuell fr eine Spalte definierte Standardwert kann nachtrglich gendert werden. Das hat natrlich keine Auswirkungen auf die schon gespeicherten Datenstze, sondern wirkt sich erst bei anschlieend neu eingefgten Stzen aus. Die Option null bzw. not null kann ebenfalls im Nachhinein verndert werden. Allerdings wird beim ndern der Option auf die Einstellung not null die gesamte Tabelle entsprechend geprft, d.h. Sie mssen die zugehrige Spalte vorher gegebenenfalls mit irgendeinem Wert fllen. In allen anderen Fllen erfolgt die nderung der Tabellenstruktur ber den Umweg einer manuell erstellten Sicherungskopie, dem Lschen und Neuanlegen der zu ndernden Spalte und dem manuellen Zurckkopieren der gesicherten Daten, wobei die in der genderten Spalte gespeicherten Werte entsprechend umformatiert werden knnen. Weitere Hinweise zu diesem Szenario finden Sie im nchsten Abschnitt, wo es um das Lschen von nicht mehr bentigten Spalten geht.

Beschreibung der Objekte

201

Das ndern einer Spaltendefinition erfolgt mit Hilfe der alter table-Anweisung zusammen mit der modify-Klausel. Dabei mssen Sie hinter dem Schlsselwort modify die zu ndernde Spalte mit ihren neuen Attributen in Klammern spezifizieren. Dabei mssen Sie nur die Attribute angeben, die wirklich gendert werden sollen. Im Folgenden finden Sie hierfr ein paar Beispiele:

alter table bezuege modify (betrag number(10,2)) modify (la default 'xxx') modify (tage null); commit;

Mit Hilfe dieses Listings werden drei Spalten der Tabelle bezuege verndert. Im ersten Fall wird der Datentyp um eine Vorkommastelle verlngert. Fr das Lohnartenfeld wird der Standardwert angepasst und bei den Tagen werden ab sofort keine Eingaben mehr bentigt. Lschen von Spalten Fr das Lschen einer Spalte existiert berhaupt kein entsprechender Befehl, d.h. in dem Fall mssen Sie fr die Tabelle zunchst eine Sicherungskopie anlegen. Danach wird die zu ndernde Tabelle gelscht und anschlieend mit der neuen Struktur wieder angelegt. Am Ende des gesamten Szenarios werden die noch bentigten Spalten aus der Sicherungskopie in die eigentliche Tabelle zurckkopiert. Beim Anlegen der Sicherungskopie knnen Sie dabei ein ganz spezielle Form des Befehls create table verwenden, denn mit Hilfe dieser besonderen Variante knnen Sie eine neue Tabelle durch Kopie bzw. aus einem Extrakt einer anderen Tabelle erstellen (vgl. Listing 2.59).
drop table cpy_bezuege; create table cpy_bezuege tablespace usr as select * from bezuege; commit;
Listing 2.59: Kopieren einer Tabelle

In anderen Datenbanksystem existiert hierfr manchmal die spezielle Variante einer select into Auswahlabfrage. Das Praktische an dieser Form des create tableBefehls ist, dass Sie sich hierbei das explizite Anlegen der neuen Tabelle durch Aufzhlen der bentigten Spalten mit allen notwendigen Attributen ersparen. Allerdings funktioniert das Ganze nur dann so reibungslos, wenn in der spezifizierten Abfrage nur Spaltennamen aus anderen Tabellen und keine Ausdrcke verwendet werden. Wenn Sie innerhalb der Abfrage Ausdrcke verwenden, dann mssen Sie diesen berechneten Spalten zum einen eine berschrift zuweisen, die spter als Feldnamen verwendet wird, und zum anderen ermittelt Oracle den geeigneten Datentyp automatisch.

202

Datenbankobjekte in einer Oracle-DB

drop table cpy_bezuege; create table cpy_bezuege tablespace usr as select a.*, 4+5 as wert2, 'haha' as text from bezuege a; commit;

In der hier gezeigten Variante erhlt die Sicherungskopie cpy_bezuege zwei zustzliche Spalten. Die erste heit WERT2 und ist numerisch und die zweite neue Spalte hat den Namen TEXT und wird als vierstellige Zeichenfolge angelegt. Nach dem erfolgreichen Erstellen der Sicherungskopie kann die alte Tabelle gelscht und mit der neuen Struktur wieder angelegt werden. Danach werden die Daten aus der Sicherungskopie zurckgeladen. Im Rahmen der dabei zu verwendenden insert-Anweisung werden gelschte Spalten weggelassen und genderte Spalten mssen entsprechend umformatiert werden. Objektorientiert Bei der Vorstellung der objektorientierten Daten- und Tabellentypen haben Sie auch schon einige Beispiele zur Anlage von objektorientierten Tabellen gesehen. Auch bin ich auf den Unterschied zwischen der Verwendung des Objektes im Rahmen einer gewhnlichen Spalte und der objektorientierten Verwendung eingegangen. Zur Erinnerung knnen Sie die alternativen Verfahrensweisen dem folgenden Listing noch einmal entnehmen.
create table h_mensch (h_m mensch) create table menschen of mensch

Wenn Sie mit Objekten arbeiten mchten oder mssen, dann wrde ich die objektorientierte Verfahrensweise bevorzugen, da der anschlieende Umgang mit der Tabelle einfacher ist; mglich sind natrlich beide Verfahren. Die ansonsten hier beschriebenen Mglichkeiten zur Anlage von Constraints, ganz gleich ob zur Anlage von Indexen, Prfungen oder Integrittsberwachung, stehen Ihnen natrlich auch bei den Objekten bzw. den objektorientierten Tabellen zur Verfgung. Im folgenden Listing finden Sie hierzu noch einmal zwei kleine Beispiele.
alter table h_mensch add constraint check_geschl check (h_m.geschl in ('M', 'W') disable alter table menschen add constraint check_geschl check (geschl in ('M', 'W') disable

Varianten Mit zwei besonderen Variationen mchte ich das Kapitel Tabellen zunchst einmal abschlieen. Zum einen geht es um den Parameter cache, den Sie zusammen mit der Anlage einer Tabelle verwenden knnen, und der dazu fhrt, dass Oracle versucht die zugehrigen Dabenblcke mglichst lange im Speicher vorzuhalten.

Beschreibung der Objekte

203

Das ist fr kleine und hufig genutzte Tabellen interessant, weil diese damit quasi immer sofort zur Verfgung stehen. Der Standardwert fr diese Option ist nocache. Zum anderen geht es um die Klausel nologging, die dazu fhrt, dass zusammen mit Einfgeoperationen weniger Protokollmaterial im redo log-Bereich anfllt. Gerade im Rahmen von Batchprozessen werden hufiger Arbeitstabellen am Anfang des Programms mit Hilfe eines truncate table-Befehls abgeschnitten, um danach wieder ber eine insert-Anweisung gefllt zu werden. In solchen Fllen oder beim Urladen irgendwelcher Daten kann diese Option interessant sein, um die Performance der Einfgeanweisung zu erhhen. Beide Klauseln knnen zusammen mit der Anlage der Tabelle oder im Nachhinein ber eine entsprechende alter table-Anweisung verwendet werden. Die nachfolgenden Beispiele zeigen Ihnen die prinzipielle Verwendung dieser Klauseln.
alter alter alter alter table table table table lohnarten lohnarten lohnarten lohnarten cache; nocache; logging; nologging;

2.2.18 Trigger (Triggers)


Bei den sogenannten Triggern handelt es sich um in der Datenbank gespeicherte PL/SQL-Programme, die durch bestimmte Datenereignisse automatisch aufgerufen (getriggert) werden. Konkret knnen diese Ereignisse in einer Tabelle durch Verwendung einer Einfge-, nderungs- oder Lschanweisung ausgelst werden (vgl. Abb. 2.16).

Datenbank

Before-Trigger

delete from ...

Lschen durchfhren

After-Trigger

Abbildung 2.16: Schema der Verwendung getriggerter Programme

204

Datenbankobjekte in einer Oracle-DB

Die Abbildung 2.16 zeigt Ihnen stark vereinfacht den internen Ablauf einer Lschanweisung bei vorhandenen Trigger-Programmen. Wird jetzt im Rahmen einer SQL-Anweisung ein delete-Kommando abgesetzt, so startet Oracle zunchst das Programm eines vorhandene Vorab-Lschtriggers. Anschlieend werden die Daten gelscht und danach startet die Datenbank automatisch das Programm des vorhandenen Danach-Lschtriggers. Dabei haben beide Trigger-Programme Zugriff auf die im Rahmen der Lschtransaktion betroffenen Datenstze und beide Programm knnten durch entsprechende Anweisungen die Transaktion abbrechen. Wie ich schon angedeutet habe, werden Trigger immer zusammen mit einer Tabelle definiert, d.h. bei der Erstellung des Triggerprogramms mssen Sie angeben, fr welche Tabelle der Trigger gestartet werden soll. Auerdem mssen Sie festlegen, ob der Trigger vor oder nach Durchfhrung der nderungstransaktion und fr welche Transaktionen der Trigger ausgefhrt werden soll, d.h. Sie haben die Mglichkeit, spezielle Einfge-, nderungs- oder Lschtrigger zu erstellen. Des weiteren mssen Sie definieren, wie der Trigger zusammen mit der durch die nderungstransaktion betroffene Datenmenge aufgerufen werden soll. Hierbei haben Sie zum einen die Mglichkeit, den Trigger zusammen mit allen betroffenen Datenstzen bzw. mit der zugehrigen SQL-Anweisung oder mit jedem Datensatz einzeln starten zu lassen. Nach Kenntnis dieser ganzen Informationen macht es Sinn, dass in Abbildung 2.16 vereinfachte Ausfhrungsmodell von Triggerprogrammen ein wenig zu przisieren. Der nun folgenden Aufstellung knnen Sie entnehmen, wie bzw. in welcher Reihenfolge Trigger gestartet werden und wie diese mit eventuell vorhandenen Constrains zusammenarbeiten: 1. Ausfhrung aller Vorab-Trigger, die nicht fr jeden einzelnen Datensatz gestartet werden sollen. 2. Durchlaufen aller im Rahmen der Transaktion selektierten Datenstze. Ausfhrung aller datensatzbezogenen Vorab-Trigger. ndern, Lschen, Einfgen des Datensatzes entsprechend des SQL-Befehls. Durchfhren alle vorhandenen Constraint-Prfungen. Ausfhrung aller datensatzbezogenen Danach-Trigger.

3. Ausfhren aller nicht datensatzbezogenen Danach-Trigger. Ein ganz beachtlicher Unterschied zu einigen anderen Datenbanksystemen ist, dass Sie fr eine Tabelle mehrere Trigger gleichen Typs, beispielsweise mehrere Vorab-Lschtrigger, definieren knnen. In dem Fall werden beim Lschen eines oder mehrere Datenstze einfach alle zugehrigen Triggerprogramme nacheinander gestartet. Aber alleine schon die Tatsache, dass Sie in Oracle die Trigger vor oder nach Durchfhrung der zugehrigen Transaktion starten knnen, ist ein beachtlicher Unterschied im Vergleich zu anderen Datenbanksystemen. Aus meiner Sicht sind die Trigger eines der interessantesten Features einer relationalen Datenbank. Es gibt unendlich viele Einsatzmglichkeiten, man knnte auch sagen, die Trigger sind die Eierlegendewollmilchsau in Ihrer Werkzeugkiste. In der folgenden Aufstellung habe ich ein paar Einsatzmglichkeiten fr Trigger auf-

Beschreibung der Objekte

205

gezhlt und dabei habe ich in Klammern festgehalten ob es sich bei dem Einsatzgebiet eher um einen Vorab- bzw. Danach-Trigger handelt.

: : : : :

(Vorab) berprfung der Transaktionsberechtigung. Drfen die Daten beispielweise aufgrund anderer Aktivitten gerade nicht gendert werden, so knnen Sie darauf mit Hilfe eines Triggers achten. Beispiel: Whrend die Gehaltsabrechnung luft, drfen bestimmte Stammdaten nicht gendert werden. (Vorab) Verhindern bestimmter Transaktionen, beispielsweise Massenupdates oder Mehrfachlschungen in Stammdatentabellen. (Danach) Automatische Berechnung verschiedener, meistens redundanter Felder. Ein einfaches Beispiel hierfr wre das Mitfhren einer Arbeitsspalte mit einer besonderen Aufbereitung der Suchbegriffe (vgl. nlssort). (Vorab + Danach) berwachung komplexer Prfroutinen, die beispielweise im Rahmen der einfachen check- oder Integritts-Constraints nicht programmiert werden knnen, weil die Regeln zu umfangreich oder die Datenstrukturen hierfr ungeeignet sind. (Vorab + Danach) Sicherstellen der referentiellen Integritt. Beispielsweise durch automatisches Lschen oder Umbenennen abhngiger Datenstze. Mit Hilfe eines Danach-Triggers knnte beispielsweise jeder Elternsatz seine Kinder lschen. Wenn Sie dieses Prinzip in Ihrer Datenbank durchhalten, dann knnen Sie anschlieend an jeder Stelle mit einer Lschanweisung ansetzen und es ist sichergestellt, dass abhngige Datenstze ebenfalls automatisch gelscht werden. (Danach) Erstellen von kontrollierten Datenredundanzen. Aus Performancegrnden kann es manchmal sinnvoll sein, bestimmte Informationen mehrfach in der Datenbank vorzuhalten. Allerdings mssen Sie dann darauf achten, dass die zugehrigen Felder und Stze immer die gleichen Werte enthalten, wozu Sie Trigger-Programme verwenden knnen. (Danach) Erstellen einer Protokollierung von nderungen auf Datensatzebene. (Vorab + Danach) Ereignisgesteuerte Administration oder soll ich besser Workflow-Management sagen. Ein Trigger bietet Ihnen das ideale Werkzeug, Datennderungen zu erkennen und daraufhin die bentigten Aktionen auszulsen, beispielsweise neue Datenstze in sogenannte todo-Listen einzutragen. (Vorab) Programmierung komplexer Zugriffsschutzbestimmungen, beispielsweise in der Form von datensatzbezogenen nderungsrechten.

: :

Das waren nur einige Beispiele fr einen mglichen Einsatz von Trigger-Programmen, wobei ich glaube, dass das groe Spektrum der Einsatzmglichkeiten deutlich geworden ist. Wenn Sie innerhalb eines Triggers weitere SQL-nderungskommandos absetzen, dann fhrt das unter Umstnden zum Auslsen weiterer Triggerprogramme, sofern fr die entsprechenden Tabellen und Transaktionen entsprechende Programme angelegt wurden (vgl. Abb. 2.17).

206

Datenbankobjekte in einer Oracle-DB

update tabelle1 ...

tabelle1 update-trigger... { insert tabelle2 }

tabelle2 insert-trigger... { delete tabelle3 }

Abbildung 2.17: Verschachtelte Ausfhrung von Triggern

Das ist im brigen auch wieder ein wichtiger Aspekt im Vergleich zu anderen Datenbanksystemen, wo es unter Umstnden Restriktionen bei der Verwendung geschachtelter Trigger gibt bzw. deren kaskadierende Ausfhrung berhaupt nicht mglich ist. Ein Trigger wird mit Hilfe der Anweisung create or replace trigger erstellt bzw. gendert. Lschen knnen Sie ihn mit Hilfe des Befehls drop trigger. In beiden Fllen mssen Sie hinter dem Befehl als Erstes den Namen des Triggers spezifizieren. Weitergehende Informationen zu Triggern finden Sie in der Oracle-Dokumentation vor allem an zwei Stellen. Zum einen enthlt das Buch Oracle8 Concepts ein eigenes Kapitel Database Triggers und zum anderen finden Sie auch in der Oracle8 SQL Reference unter dem Stichwort create trigger Informationen und Beispiele zur Anlage und Verwendung dieser speziellen Programme. Beispiel An dieser Stelle mchte ich zunchst nur ein sehr einfaches Beispiel anfhren und als Variation lediglich die Anlage unterschiedlicher leerer Triggerrmpfe darstellen. Der Grund dafr ist, dass die Erstellung von Triggern schnell zu umfangreicheren Programmpassagen fhrt und ich mchte hier und jetzt nicht dem gesamten Kapitel PL/SQL-Programmierung, in dem Sie weitere und vor allem komplexere Beispiele finden, schleichend vorgreifen mssen. Als Erstes erstellen wir einen Trigger fr die Lohartentabelle, der dafr sorgt, dass jegliche nderungen fr die Tabelle nur noch an bestimmten Wochentagen mglich sind (vgl. Listing 2.60).
create or replace trigger lohnarten_upd before update on lohnarten begin if to_char(sysdate,'D') not in ('5','7') then

Beschreibung der Objekte

207

raise_application_error(-20001, 'Die Tabelle kann nur am DO und SA gendert werden.'); end if; end; / show errors; commit;
Listing 2.60: Beispiel fr die Anlage eines Vorab-Triggers

Wie Sie dem Listing 2.60 entnehmen knnen, erhlt jeder Trigger bei der Anlage einen Namen (lohnarten_upd). Anschlieend folgen verschiedene Anweisungen die festlegen, wann und wofr der Trigger gestartet werden soll, was ich gleich noch ausfhrlicher erlutern werde. Das eigentliche Trigger-Programm befindet sich dann wieder in einem begin..end-Block. In unserem Beispiel ermitteln wir innerhalb des Programms mit Hilfe der Funktionen to_char und sysdate den Wochentag aus dem aktuellen Tagesdatum. Ist dieser Wert nicht fnf und nicht sieben (Donnerstag bzw. Samstag), dann brechen wir mit Hilfe der Funktion raise_application_error die Transaktion ab und stellen dem aufrufenden Anwendungsprogramm eine entsprechende Fehlermeldung zur Verfgung. Varianten Die Deklaration eines Triggers folgt im Prinzip folgendem Schema:
create or replace trigger <Trigger-Name> <Zeitpunkt> <Transaktion> on <Tabellenname> <fr Transaktion oder jeden Datensatz> <Ausfhrungsbedingung>

Der vergebene Name des Triggers muss innerhalb des verwendeten Schemas eindeutig sein. Zur Spezifizierung des Zeitpunkts knnen Sie die Schlsselwrter before oder after verwenden, um entsprechend einen Vorab- bzw. Danach-Trigger zu erstellen. Die den Trigger aufrufende Transaktion legen Sie mit Hilfe der Schlsselwrter insert, update oder delete (Einfgen, ndern und Lschen) fest. Hierbei knnen Sie die einzelnen nderungsarten miteinander kombinieren, indem Sie diese mit dem Wrtchen or verbinden.
insert or update or delete

In dem Fall knnen Sie innerhalb des Programms mit Hilfe der Schlsselwrter inserting, updating bzw. deleting auf die jeweils verantwortliche nderungsanweisung reagieren; ein Beispiel hierfr finden Sie am Ende des Abschnitts.
if inserting then ... if updating then ... if deleting then ...

208

Datenbankobjekte in einer Oracle-DB

Zusammen mit einer nderungstransaktion (update) knnen Sie dabei auch noch einzelne Spalten festlegen, so dass der Trigger bei einer update-Anweisung lediglich dann aufgerufen wird, wenn eine der aufgefhrten Spalten dabei gendert wird.
insert or update of la, la_text or delete

Nachdem nun die Transaktionsarten fr den Trigger festgelegt sind, folgt als Nchstes hinter dem Wrtchen on der Namen der zugehrigen Tabelle. Danach legen Sie fest, ob der Trigger fr die gesamte Transaktion oder fr jeden einzelnen betroffenen Datensatz gestartet werden soll. Dabei entspricht das einmalige Starten des Triggers fr die gesamte Transaktion dem Standardverfahren. Um den Trigger fr jeden betroffenen Datensatz aufzurufen, mssen Sie die Klausel for each row spezifizieren. Zusammen mit den datensatzbezogenen (for each row) Triggern knnen Sie auch noch eine Ausfhrungsbedingung festlegen, die fr den Datensatz erfllt sein muss, damit das Triggerprogramm gestartet wird. Diese Klausel leiten Sie mit dem Schlsselwort when ein, dem die konkrete Ausfhrungsbedingung in Klammern folgt. Hierbei knnen Sie mit Hilfe der Schlsselwrter new und old auf die genderten bzw. ursprnglichen Werte der betroffenen Datenstze zugreifen. Im folgenden Beispiel wird das Triggerprogramm nur dann gestartet, wenn die neue Lohnart den Wert 400 oder die alte Lohnart den Wert 233 enthlt.
for each row when (new.la = '400' or old.la = '233')

Innerhalb des Programms eines datensatzbezogenen Triggers erfolgt der Zugriff auf die alten bzw. neuen Werte durch Verwendung von :new bzw. :old.
If :new.la = '400' or :old.la = '233' then

Das war schon fast alles und bevor ich noch kurz auf eine ganz besondere Triggervariante eingehe, finden Sie im Folgenden noch verschiedene Beispiele und Variationen zur Definition von Triggerprogrammen.

: :

Erstellen eines Vorab-Triggers fr alle nderungstransaktionen


create or replace trigger mtabelle_t1 befor insert or update or delete on mtabelle

Erstellen eines Vorab-Triggers fr jeden betroffenen Datensatz, der allerdings nur dann gestartet wird, wenn die neue Lohnart grer 900 ist.
create or replace trigger mtabelle_t2 before insert or update(la) or delete on mtabelle for each row when (new.la > '900')

Erstellen eines Danach-Triggers, der nach einer Lschoperation aufgerufen wird.


create or replace trigger mtabelle_t3 after delete on mtabelle

Beschreibung der Objekte

209

Erstellen eines Danach-Triggers, der nach dem Lschen fr jeden betroffenen Datensatz gestartet wird, sofern die Lohnart kleiner dem Wert 788 ist.
create or replace trigger mtabelle_t4 after delete on mtabelle for each row when (old.la < '788')

Instead of-Trigger Mit dieser besonderen Variante knnen Sie das eigentlich Verbotene mglich machen. Konkret geht es darum, Views, die aufgrund ihrer komplexen bzw. speziellen Definition eigentlich nur gelesen werden knnen, mit Hilfe des Triggers updatefhig zu machen. Hierbei mssen Sie im Triggerprogramm die bentigten Regeln definieren, unter welchen Bedingungen die jeweils an der View beteiligten Tabellen gendert werden sollen. Bevor Sie jetzt allerdings die rmel hochkrempeln, um das gleich folgende Beispiel einzutippen, sollten Sie zunchst einmal wieder die View v$options befragen, ob dieses spezielle Feature berhaupt in Ihrer Datenbank verfgbar ist. Mein Beispiel habe ich in Anlehnung an das in der Oracle-Dokumentation vorgestellte Muster erstellt. Stellen wir uns vor, in unserer Datenbank, die wir zusammen mit einem anderen Anwender gemeinsam nutzen, existieren die beiden Tabellen meine_freunde und deine_freunde mit jeweils folgendem Aufbau.
drop table meine_freunde; drop table deine_freunde; / create table meine_freunde ( name varchar(50), telefon varchar(30) ) tablespace usr; / create table deine_freunde ( name varchar(50), telefon varchar(30) ) tablespace usr; commit
Listing 2.61: Vorbereiten eines instead of-Triggers

In diesen beiden Tabellen knnen anschlieend unabhngig voneinander entsprechende Datenstze gespeichert werden. Damit die Tabellen im Folgenden nicht ganz so leer sind, werden wir einmal jeweils zwei Datenstze einfgen.
insert into insert into insert into insert into commit; meine_freunde meine_freunde deine_freunde deine_freunde values values values values ('Hildegard', '983932'); ('Ernst', '587332'); ('Paul', '213984'); ('Sonja', '390928');

210

Datenbankobjekte in einer Oracle-DB

Mit Hilfe einer View knnen Sie nun eine Abfrage erstellen und dauerhaft speichern, mit der alle vorhandenen Freunde angezeigt werden. Hierbei soll mit Hilfe einer zustzlichen Spalte dargestellt werden, aus welchem Tpfchen der jeweilige Freund selektiert wurde.
create view alle_freunde as select name, telefon, 'meine' as mein_dein from meine_freunde union all select name, telefon, 'deine' from deine_freunde; commit;
Listing 2.62: Mischen zweiter Tabelle mit Hilfe einer union-View

Im Rahmen der in der View gespeicherten Abfrage werden zwei exakt gleich aufgebaute select-Abfragen mit Hilfe der union-Anweisung gemischt. Als Ergebnis erhalten Sie eine logische Tabelle, deren Abfrage (vgl. Listing 2.63) den Eindruck erweckt, als wrden die zugehrigen Einzelstze gemeinsam gespeichert werden.
SQLWKS> select * from alle_freunde 2> NAME ----------------------------------Hildegard Ernst Paul Sonja 4 rows selected.

TELEFON -----------------------983932 587332 213984 390928

MEIN_ ----meine meine deine deine

Listing 2.63: Abfrage des gemeinsamen Freundeskreises

Das Bearbeiten der in der logischen Tabelle bzw. der View zusammengefassten Datenstze ist aber von Hause aus nicht mglich. Woher soll die Datenbank bei einer Einfgeanweisung der Art
insert into alle_freunde values ('Helgo', '758473', 'meine')

auch wissen, in welchen Topf sie den neuen Datensatz einfgen soll, zumal der als Letztes bergebene Wert nicht einmal einer konkret vorhandenen Spalte entspricht? Mit Hilfe der hier besprochenen instead of-Trigger knnen Sie dieses Dilemma allerdings auflsen und der Datenbank erklren, was sie mit den einzelnen nderungen tun soll (vgl. Listing 2.64).
create or replace trigger alle_freunde instead of insert on alle_freunde for each row

Beschreibung der Objekte

211

begin if :new.mein_dein = 'meine' then insert into meine_freunde values(:new.name, :new.telefon); else insert into deine_freunde values(:new.name, :new.telefon); end if; end; / show errors; commit;
Listing 2.64: Erstellen eines einfachen instead of-Triggers

Erst jetzt knnen Sie die oben abgebildete Einfgeanweisung ausfhren und erhalten als Ergebnis einen neuen Datensatz in der Tabelle meine_freunde. Wie Sie dem Beispiel entnehmen knnen, wird mit Hilfe des bergebenen Wertes fr die konstruierte Spalte meine_deine innerhalb des Programms entschieden, in welcher Tabelle die Einfgeoperation durchgefhrt werden soll. Natrlich knnen Sie das Programm auch noch um Methoden fr das ndern oder Lschen von Datenstzen oder sogar eine spezielle Variante zur Behandlung von Datenstzen, die mit dem Zusatz unsere gendert werden, erweitern. Das Letztere berlasse ich Ihnen, fr das ndern und Lschen mchte ich aber noch eine vollstndige Programmversion vorstellen.
create or replace trigger alle_freunde instead of insert or update or delete on alle_freunde for each row begin if inserting then if :new.mein_dein = 'meine' then insert into meine_freunde values(:new.name, :new.telefon); else insert into deine_freunde values(:new.name, :new.telefon); end if; elsif updating then if :new.mein_dein = 'meine' then update meine_freunde set name = :new.name, telefon = :new.telefon where name = :old.name and telefon = :old.telefon; else update deine_freunde set name = :new.name, telefon = :new.telefon where name = :old.name and telefon = :old.telefon; end if; else if :old.mein_dein = 'meine' then

212

Datenbankobjekte in einer Oracle-DB

delete meine_freunde where name = :old.name and telefon = :old.telefon; else delete deine_freunde where name = :old.name and telefon = :old.telefon; end if; end if; end; / show errors; commit;
Listing 2.65: Triggervariante zur Herstellung der nderungsfhigkeit einer View

Mit Hilfe einer if-Anweisung reagiert das Programm auf die einzelnen zum Aufruf des Triggers gefhrten nderungsabfragen. Dabei wird in allen Fllen mit Hilfe der Spalte mein_dein unterschieden, in welcher Tabelle die nderung konkret durchgefhrt werden soll. Nach Erstellung des Triggers knnen Sie auch nderungs- oder Lschabfragen zusammen mit der View alle_freunde verwenden.
update alle_freunde set telefon = '1111' where name = 'Hildegard' and mein_dein = 'meine' delete alle_freunde where name = 'Paul' and mein_dein = 'deine' commit

Varianten Jeder Segen kann auch mal zum Fluch werden. Hiermit meine ich die Situation, in dem die automatisch gestarteten Triggerprogramme beispielsweise im Rahmen von Wartungs- oder Korrekturaktionen lstig werden. In dem Fall mssen Sie den Trigger allerdings nicht unbedingt lschen, sondern es besteht auch die Mglichkeit, vorbergehend aus- bzw. einzuschalten. Hierzu finden Sie im SQL-Befehlssatz die Anweisung alter trigger, die zusammen mit den schon bekannten Klauseln disable bzw. enable zum Aus- oder Einschalten eines Triggers verwendet werden kann.
alter trigger lohnarten_upd disable; alter trigger lohnarten_upd enable;

2.2.19 Ansicht (Views)


Bei einer sogenannten View handelt es sich um in der Datenbank gespeicherte Abfrage, die sich nach auen wie eine logische Tabelle verhlt, d.h. die View knnen Sie in einem gewissen Umfang wie eine gewhnliche Tabelle verwenden, obwohl sie keine eigenen Daten enthlt. Mit Hilfe einer solchen View knnen Daten aus einer anderen Tabelle bzw. anderen Tabellen abgefragt werden, d.h. bei

Beschreibung der Objekte

213

deren Verwendung innerhalb einer Abfrage werden zustzlich auch die in der View gespeicherten Anweisungen ausgefhrt. Die Anlage einer View erfolgt mit Hilfe des Befehls create or replace view. Gelscht wird sie mit Hilfe des Befehls drop view. Dabei sieht das Anlegen einer View sieht so hnlich aus wie das Kopieren einer Tabelle mit dem create table as-Befehl. Allerdings wird hierbei statt des Wrtchens table das Wort view verwendet und im Unterschied zum Kopiervorgang werden bei der Anlage der View keine Daten bewegt, sondern es wird lediglich die SQL-Abfrage gespeichert.
create or replace view <Viewname> as select <Abfrage>

Innerhalb der in der View verwendeten Abfrageanweisung knnen Sie eine einzige Tabelle verwenden oder aber auch mehrere Tabellen miteinander verknpfen. Ebenfalls mglich ist die Verwendung von mischenden (union) oder gruppierenden (group by) Abfragen. Insgesamt ergibt sich fr das Einsatzgebiet von Views das folgende Spektrum:

: :

Speichern komplexer Abfragen, um zum einen deren Verwendbarkeit zu vereinfachen oder aber auch zum anderen dem Endanwender die Ausfhrung der Abfrage berhaupt zu ermglichen. Views knnen auch ein wichtiger Bestandteil eines Sicherheitskonzepts sein. Wie Sie spter in diesem Buch noch erfahren werden, muss der Zugriff auf die einzelnen Schema-Objekte fr andere Benutzer explizit freigegeben werden. Hat ein Benutzer Zugriff auf eine View, so kann er die dort definierten Spalten und Stze abrufen, ohne dass er Zugriffsrechte auf die darunter liegenden Tabellen besitzen muss. Konstruktion einer logischen Schicht zwischen Anwendungen, beispielsweise Reports, und der Datenbank, um diese Anwendungen zumindest in einem gewissen Mae resistent gegen Strukturnderungen zu machen.

Gerade fr den ersten der aufgefhrten Punkte finden Sie schon alleine im Systembereich von Oracle viele Beispiele. Im Rahmen der Tabellenerstellung haben wir hufiger einfache Abfragen auf die View dba_extents gemacht.
select extent_id, bytes, blocks from dba_extents where segment_name = 'LOHNARTEN'

Dass diese Abfrage so einfach war, liegt daran, dass die eigentliche Komplexitt in der View versteckt ist, denn die dort gespeicherte Auswahlanweisung ist folgende:
select ds.owner, ds.segment_name, ds.partition_name, ds.segment_type, ds.tablespace_name, e.ext#, f.file#, e.block#, e.length * ds.blocksize, e.length, e.file# from sys.uet$ e, sys.sys_dba_segs ds, sys.file$ f where e.segfile# = ds.relative_fno and e.segblock# = ds.header_block and e.ts# = ds.tablespace_id and e.ts# = f.ts# and e.file# = f.relfile#

214

Datenbankobjekte in einer Oracle-DB

Die in einer View gespeicherte Anweisung knnen Sie brigens durch eine Abfrage auf das Objekt all_views ermitteln. Ansonsten passt das Beispiel auf alle drei von mir genannten Kategorien. Die Zusammenfassung dieser doch recht umfangreichen Abfrage zu einem Objekt vereinfacht uns allen deren Verwendung. Zum zweiten bentigen und besitzen wir blicherweise berhaupt keine Zugriffsrechte auf die in der View verwendeten Objekte (z.B. sys_dba_segs). Und drittens knnte Oracle die konkrete Speicherung von Segment- bzw. Extent-Informationen ndern, ohne dass wir das berhaupt mitbekommen, sofern die View dba_extents nach einer solchen nderung immer noch die gleichen Daten liefert. In Bezug auf die technische Verwendung bzw. Ausfhrung eines View-Objekts, unterscheidet sich Oracle von manchen anderen Datenbanksystemen. Primres Ziel ist es nmlich, nicht die eigentliche View auszufhren und das zugehrige Abfrageergebnis zusammen mit der eigentlichen auslsenden Abfrage zu verknpfen, sondern die in der View gespeicherte Abfrageanweisung mit dem aufrufenden SQL-Statement zu mischen (vgl. Abb. 2.18).

Abfrage: select * from v_bezuege where la = 100

View v_bezuege: select persnr, la from bezuege where la < 900

select a.persnr, a.la from bezuege a where (a.la < 900) and (a.la = 100)

Datenbank

Abbildung 2.18: Mischen der View-Auswahlanweisung mit dem rufenden SQL-Statement

Diese Vorgehensweise hat den Vorteil, dass bei der Ausfhrung der View die in den Tabellen spezifzierten Indices bei der Datenauswahl bercksichtigt werden knnen, so dass mit der Verwendung von Views meistens keine Geschwindigkeitseinbuen einhergehen. Meistens bedeutet demnach aber, dass es auch Ausnahmen gibt. Das ist beispielsweise dann der Fall, wenn Oracle die in der View gespeicherten Auswahlanweisungen nicht zu der aktuell verwendeten Abfrage hinzumischen kann, was unter anderem immer dann passiert, wenn die View folgende Anweisungen enthlt:

: : : :

eine connect by-Klausel. die Verwendung von Mengenoperationen (union, union all, minus usw.). gruppierende Abfragen (group by, sum, max, min usw.). die Pseudospalte rownum.

Beschreibung der Objekte

215

In solchen Fllen wird die View ausgefhrt und das Ergebnis wird zunchst einmal in einem temporren Bereich zwischengespeichert. Diese temporre Tabelle wird anschlieend mit den anderen an der Abfrage beteiligten Tabellen verknpft, was die Performance der Abfrage durchaus negativ beeinflussen kann. Beim Analysieren Ihrer SQL-Abfrage knnen Sie genau ablesen, ob Ihre View ausgefhrt oder zur Abfrage hinzugemischt wird. Genauere Informationen hierzu erhalten Sie in diesem Workshop bei der Behandlung des Abfragetunings. Ein weiterer Aspekt bei den Views ist die Fragestellung, ob diese Objekte auch zusammen mit nderungsabfragen verwendet werden knnen. Dabei sind einfache Views, deren Abfrage lediglich eine Tabelle verwendet, meistens nderungsfhig, sofern innerhalb der Views folgende Anweisungen nicht verwendet wurden: der distinct-Befehl. Aggregatfunktionen (z.B. avg, count, max, min, sum usw.) bzw. Gruppieroperationen (z.B. group by). Mengenoperationen (union, union all, minus usw.). die Befehle start with oder connect by. die Pseudospalte rownum.

Auch eine View, in der verschiedene Tabellen verknpft werden, kann in einem gewissen Umfang nderungsfhig sein. Generell gilt allerdings, dass die eingesetzte nderungsabfrage nur eine der in der View verwendeten Tabellen ndern darf. Welche Spalten einer View im Zweifel gendert werden drfen, knnen Sie mit Hilfe einer Abfrage auf die View user_updatable_colums ermitteln.
select column_name, updatable from user_updatable_columns where table_name = '<Name der View>'

Wie Sie im vorhergehenden Kapitel jedoch gesehen haben, gibt es mit Hilfe der instead of-Trigger immer eine Mglichkeit, den einzelnen Views die Updatefhigkeit selbst dann beizubringen, wenn sie standardmig gar keine nderungsanweisung zulsst.

Beispiel Als Beispiel erstellen wir jetzt eine View (vgl. Listing 2.66), die uns alle vorhandenen Bezge zusammen mit dem Lohnartentext aus der Lohnartentabelle anzeigt.

create or replace view ma_bezuege as select a.persnr, a.la, b.la_text, a.betrag from bezuege a, lohnarten b where b.la = a.la and a.betrag <> 0; commit;
Listing 2.66: Erstellen einer einfachen View

216

Datenbankobjekte in einer Oracle-DB

Wie Sie dem Beispiel entnehmen knnen, wird die View ma_bezuege mit Hilfe der Anweisung create or replace view angelegt. Die Verwendung dieser Form hat als Alternative zu der Kombination einzelner drop view bzw. create view-Anweisungen wieder den Vorteil, dass eventuell zugewiesene Zugriffsrechte hierbei erhalten bleiben. Hinter dem Namen der View folgt das Wrtchen as, dem die eigentliche in der View gespeicherte Abfrage folgt. Die Verwendung unseres neuen Objekts in einer Abfrage fhrt nun alle betragsmig gespeicherten Bezge zusammen mit der Lohnartenbezeichnung zu Tage.
SQLWKS> select * from ma_bezuege 2> PERSNR LA LA_TEXT BETRAG ---------- --- -------------------------------------------- ---------4711 100 Grundgehalt 1000 1 row selected.

Eine weitere Abfrage auf die View user_updatable_columns beschert uns Gewissheit, dass ohne zustzliche Objekte in Form eines instead of-Triggers unsere View eine reine Leseveranstaltung ist.
SQLWKS> select column_name, updatable from user_updatable_columns 2> where table_name = 'ma_bezuege' 3> COLUMN_NAME UPD ------------------------------ --0 rows selected.

2.2.20 Zusammenfassung
Am Anfang des Kapitels hatte ich Ihnen einen berblick ber die in Oracle verfgbaren Objekte versprochen. Wie gut, dass das Wrtchen berblick nicht automatisch den zugehrigen Umfang impliziert, denn bei meinem Streifzug durch die Schema-Objekte der Oracle-Datenbank ist ein beachtliches Hufchen Papier entstanden. Trotzdem gibt es natrlich immer Leser, die gerade die eine spezielle Variante eines Befehls vermissen. Doch irgendwie muss man den Rahmen abstecken; schon alleine fr die Befehle create oder alter table knnte man locker ein eigenes Buch mit ber 200 Seiten erstellen, wenn man alle Variationsmglichkeiten dieser beiden Befehle beschreibt. Dabei ist es zum Teil sicher auch ein bisschen willkrlich, dass man die eine Variante noch beschreibt, eine andere Variation aber weglsst. In meiner mittlerweile zehnjhrigen Erfahrung mit verschiedenen Datenbanken habe ich von Zeit zu Zeit auch immer neue Systeme kennen gelernt. Dabei wre ich jedes Mal froh gewesen, wenn ich eine hnliche bersicht fr den Schnelleinstieg zur Verfgung gehabt htte. Ich hoffe, das geht Ihnen ebenso, wobei ich fr konstruktive Verbesserungsvorschlge natrlich immer offen bin.

Beschreibung der Objekte

217

Vielleicht sind Sie nach dieser Einfhrung aber auch ein wenig beeindruckt. Wenn Sie schon andere Datenbanksysteme kennen, dann mssen Sie zugeben, dass der Katalog der Mglichkeiten ziemlich umfangreich ist. Sofern Sie mit einer Standardsoftware (z.B. PeopleSoft) arbeiten, dann fragen Sie sich jetzt vielleicht aber auch, warum von diesen Mglichkeiten fast kein Gebrauch gemacht wird. Es ist eigentlich nur selten mglich, mit der Einfhrung einer neuen Software auch den Einsatz eines ganz bestimmten DBMS zu erzwingen. Dies muss man bei der Konzeption bzw. Entwicklung von Standardsoftware bercksichtigen, wenn man sich nicht von vornherein auf einen bestimmten Markt beschrnken will. Vergleicht man nun aber die verschiedenen gngigen DBMS-Systeme (Oracle, Sybase, SQL-Server, Informix, DB/2, Gupta), dann stellt man fest, dass der kleinste gemeinsame Nenner in der Tat ziemlich klein ist. Aus Sicht der Oracle-Datenbank werden bestimmte Funktionalitten (z.B. selbstdefinierte Funktionen) von den meisten anderen Produktion berhaupt nicht untersttzt. Andere Objekte (z.B. Trigger) gibt es zwar auch, aber sie haben im Vergleich zu Oracle zum Teil einen eingeschrnkten Funktionsumfang (z.B. nur ein Trigger pro Tabelle) oder wichtige Details in Bezug auf die Erstellung oder Verwendung unterscheiden sich sehr stark. Konkret bedeutet das fr den Entwickler, dass wenn er den universellen Markt bedienen will, nur Tabellen, explizit definierte Indices und Views verwenden darf, wobei er selbst hierbei noch Zurckhaltung in Bezug auf die verwendeten Datentypen und die Gestaltung der bentigten Abfragen Zurckhaltung ben muss. Das ist der Grund, warum die Datenbank einer Standardsoftware oftmals so einfach gestrickt ist; gehen Sie ruhig davon aus, dass die zustndigen Programmierer es besser gekonnt htten, wenn Sie ein Oracle-Produkt entworfen htten. Wenn Sie spezifisch auf Oracle-Datenbanken zugeschnittene Entwicklung betreiben, dann muss Sie das alles natrlich nicht kmmern. Selbst wenn Sie im Rahmen eines Einfhrungsprojekts Erweiterungen durchfhren kann es sinnvoll sein im Rahmen der jeweiligen Aufgabenstellung weitergehenden Datenbankfunktionalitten zu nutzen. Allerdings sollte dabei allen klar sein, dass der Wechsel des Standardprodukts auf ein andere Datenbank immer noch mglich, die Portierung der individuellen Erweiterungen jedoch vielleicht nur mit zustzlichem Aufwand oder sogar gar nicht mglich ist. Was ich hiermit sagen will und sich vor allem an meine Beraterkollegen richtet ist, dass der tiefe Griff in die Trickkiste ist nicht immer das Ma aller Dinge ist. Es drfte jeder Fachabteilung schwer verstndlich zu machen sein, dass sie auf der einen Seite ein nach Herstellerangaben berall lauffhiges Produkt gekauft hat, das aber auf der anderen Seite wegen der individuell durchgefhrten Anpassungen nicht mehr portierbar ist. Wenn natrlich Klarheit ber diesen Sachverhalt herrscht und in absehbarer Zeit auch kein Wechsel des DBMS geplant ist, dann spricht aus meiner Sicht allerdings nichts dagegen, im Rahmen von Anpassungen und Erweiterungen weitergehende Datenbankfunktionalitten einzusetzen.

218

Datenbankobjekte in einer Oracle-DB

Nach diesem mahnenden Fingerzeit an die Spieler und Fummler noch ein abschlieender Hinweis. Grundstzlich finden Sie in der Oracle-Dokumentation unter dem Link Oracle8 Concepts weiterfhrende und zusammenhngende Erluterungen zu den verschiedenen Schema-Objekten. Im Buch PL/SQL Users Guide and Reference finden Sie weitergehende Informationen zu den mit PL/SQL-Erstellten Schema-Objekten wie zum Beispiel Funktionen oder Prozeduren. Daneben gibt es noch den Link Oracle8 SQL-Reference. Hier finden Sie fr alle Befehle die vollstndige Beschreibung der Syntax aller Befehle sowie eine detaillierte Beschreibung der mglichen Parameter und Varianten. Sollten Sie whrend der Objekterstellung oder beim Testen derselben mal eine Fehlermeldung erhalten, dann knnen Sie die genaue Bedeutung des Fehlers nebst Hinweise zu dessen Behebung ebenfalls der Oracle-Dokumentation entnehmen, indem Sie dem Link Oracle8 Error Messages folgen. Dort finden Sie eine nach Kategorie bzw. Produkt und Fehlernummer sortierte Auflistung aller Fehlermeldungen.

2.3

Die Beispieldatenbank anlegen

Im weiteren Verlauf des zweiten Kapitels werden wir nun eine kleine Beispieldatenbank anlegen, genauer gesagt legen wir dabei natrlich nur ein eigenes Schema in unserer vorhandenen Datenbank an. Das besteht natrlich nicht wie im richtigen Leben gleich aus hunderten von Tabellen, aber eine kleine Struktur (vgl. Abb. 2.19) kommt dennoch schon zustande. Nach dem Anlegen der entsprechenden Objekte, die wir vor allem bei den der Behandlung der Abfragen im nchsten und bei der PL/ SQL-Programmierung im bernchsten Kapitel bentigen, werden wir die leeren Tabellen mit Daten fllen. Hierbei werden Sie verschiedene Mglichkeiten kennen lernen. In jedem Fall stammen die Daten aus einer Access-Datenbank, die Sie auf der Begleit-CD im Verzeichnis \DATEN finden. Konkret finden Sie dort die beiden Access-Datenbanken MISCH97.MDB und MISCH2000.MDB entsprechend der jeweiligen Access-Versionen. Ebenfalls dort gespeichert sind auch eine Reihe von Textdateien, die auf verschiedene Verfahrensweisen aus der Access-Datenbank exportiert wurden und die im Anschluss an die Fertigstellung des eigenen Schemas importiert werden sollen. Die beiden Access-Datenbanken bentigen Sie in diesem Kapitel also nicht direkt, es sei denn, Sie wollen den Export der beschriebenen Textdateien ausprobieren. Auerdem besteht die Mglichkeit, sich eine Migrationshilfe fr Access-Datenbanken zu installieren und sofern Sie diese einmal ausprobieren mchten, dann finden Sie in diesen beiden Access-Datenbanken entsprechendes Eingabematerial fr den Migrations-Assistenten.

Die Beispieldatenbank anlegen

219

personalien (
persnr varchar2(11) not null, name varchar2(50) not null, strasse1 varchar2(35), strasse2 varchar2(35), strasse3 varchar2(35), strasse4 varchar2(35), ort varchar2(30), land varchar2(3), bland varchar2(6), plz varchar2(12), telefon varchar2(24), geschlecht varchar2(1) not null, familienstd varchar2(1) not null, familienstd_dt date, gebdatum date not null, gebort varchar2(30), gebland varchar2(3) not null)

laender ( land varchar2(3) not null, bland varchar2(1) not null, bezeichnung varchar2(30))

blaender (
land varchar2(3) not null, bland varchar2(6) not null, bezeichnung varchar2(30))

bvs (
persnr varchar2(11) not null, lfdnr smallint not null, eintrt date not null, austrt date, ausgrd varchar(3), unternehmen varchar(3) not null)

austrittsgruende (
ausgrd varchar2(3) not null, gab date not null, status varchar2(1) not null, bezeichnung varchar2(30) not null )

unternehmen (
unternehmen varchar2(3) not null, gab date not null, status varchar2(1) not null, bezeichnung varchar2(30) not null )

gehalt ( persnr varchar2(11) not null, lfdnr smallint not null, gab date not null, kst varchar2(10) not null, gehalt number(9,2) not null, zulage number(9,2) not null )

kostenstelle (
unternehmen varchar2(3) not null, kst varchar2(10) not null, gab date not null, status varchar2(1) not null, bezeichnung varchar2(30) not null )

Abbildung 2.19: Struktur unseres Beispiel-Schemas

2.3.1

Anlage des Schema-Eigners

Am Anfang des Kapitels haben Sie den Begriff des Schemas kennen gelernt. Bisher haben wir bei allen unseren Beispielen immer mit einem der standardmig vorhandenen Administratorenkennungen (z.B. system) gearbeitet, was sich im Folgenden nun ndern soll. Aus diesem Grund legen wir gleich zunchst einmal eine neue Benutzerkennung an. Im Vorgriff auf das bernchste Kapitel Benutzer und Rollen will ich an dieser Stelle allerdings nur soviel dazu sagen: In Oracle existieren fr die Zuweisung von Benutzerrechten im Prinzip zwei Mglichkeiten. Zunchst einmal knnen Sie einem einzelnen Benutzer individuelle Einzelrechte

220

Datenbankobjekte in einer Oracle-DB

zuweisen oder entziehen. Das wrde aber selbst bei kleinen Datenbanken mit vielleicht zehn oder zwandzig Benutzern selbst bei nur geringen Einzelrechten nicht sehr lange Spa machen, weshalb es in Oracle das Konzept der Rollen gibt. Hierbei werden verschiedene Einzelrechte zu einer sogenannten Rolle zusammengefasst und im Anschluss daran werden den jeweiligen Benutzern die einzelnen Rollen zugewiesen, wodurch der indirekt seine Einzelrechte erhlt. Aus dem Grund legen wir zunchst die neue Rolle rbeispiel an und weisen der Rolle eine Reihe von weitreichenden Einzelrechten zu (vgl. Listing 2.67). Was diese einzelnen Rechte bedeuten und welche wirklich gebraucht werden oder vielleicht auch entfallen knnten, das erfahren Sie wie schon gesagt ein paar Seiten weiter im Kapitel Benutzer und Rollen. Die in dem Zusammenhang gleich abgebildeten und beschriebenen Listings finden Sie auf der CD in der Datei \DATEN\SCHEMA.SQL.
drop role rbeispiel; create role rbeispiel; commit; / grant alter session, alter tablespace, alter user, analyze any, become user, create cluster, create database link, create procedure, create public database link, create public synonym, create rollback segment, create sequence, create session, create snapshot, create synonym, create table, create tablespace, create trigger, create user, create view, drop public database link, drop public synonym, drop rollback segment, drop tablespace, drop user, grant any role, manage tablespace, resource, exp_full_database, imp_full_database

Die Beispieldatenbank anlegen

221

to rbeispiel with admin option; commit;


Listing 2.67: Anlegen unserer Musterrolle rbeispiel

Zugegebenerweise zchten wir uns einen kleinen Administrator heran, aber bei der Anlage eines Schemas, zum Beispiel whrend der Installation einer Anwendung sind solche Rechte gar nicht schlecht. Nach einer Installation knnen die Befugnisse des Schema-Eigners im Bedarfsfall ja wieder reduziert werden. Die Befehle zum Lschen bzw. Anlegen einer Rolle heien drop role bzw. create role, wobei in beiden Fllen der Name der jeweiligen Rolle folgt. Anschlieend weisen wir der Rolle mit Hilfe entsprechender grant-Kommandos die gewnschten Einzelrechte zu. Im nchsten Schritt legen wir den Schema-Eigner an, den wir mit ubeispiel benennen wollen, wobei Sie das Skript in der Datei \DATEN\USER.SQL finden.
drop user ubeispiel cascade; commit; / create user ubeispiel identified by manager default tablespace usr temporary tablespace temporary profile default account unlock quota unlimited on usr quota unlimited on indx quota unlimited on temporary; commit;
Listing 2.68: Anlegen des Schema-Eigners ubeispiel

Der erste Teil des Skripts lscht den Benutzer ubeispiel. Hierbei sorgt die Klausel cascade dafr, dass dies auch dann passiert, wenn der Benutzer Eigentmer irgendwelcher Objekte ist, wobei seine Besitztmer in dem Fall natrlich auch gelscht werden. Im zweiten Teil des Skripts wird der Benutzer wieder angelegt. Whrend der Anlage erhlt er das Passwort manager, bekommt als Tablespace-Standard usr zugewiesen und erhlt durch die quota-Klauseln ein uneingeschrnktes Platzangebot fr die Tablespaces usr, indx und temporary. Im nchsten Schritt mssen Sie dem neuen Benutzer noch die Rolle rbeispiel zuweisen, was wiederum mit Hilfe einer grant-Anweisung passiert.
grant rbeispiel to ubeispiel;

222

Datenbankobjekte in einer Oracle-DB

2.3.2

Verwalten der Tablespaces

Beim Anlegen eines umfangreichen Schemas bzw. vor allem beim Laden der zugehrigen Daten kann es schon einmal passieren, dass ein Tablespace voll wird, was dann zum Abbruch aller gerade aktiven und auf den ihn zugreifenden Transaktionen fhrt. In dem Fall mssen Sie den Tablespace vergrern, wobei Sie hierfr verschiedene Variationsmglichkeiten haben. Vergrern des zugrundeliegenden Datenfiles Das ist sicherlich die einfachste aller mglichen Varianten. Sie setzt allerdings voraus, dass auf dem Datentrger noch ausreichend Platz zur Verfgung steht. In dem Fall knnen Sie versuchen die zum Tablespace gehrende Datei zu vergrern oder den automatischen Extent-Modus fr die Datei einzuschalten bzw. zu erweitern.
alter database datafile 'E:\ORANT\DATABASE\DB01\USR1DB01.ORA' resize 9606K; alter database datafile 'E:\ORANT\DATABASE\DB01\USR1DB01.ORA' autoextend on next 3K maxsize unlimited;
Listing 2.69: Vergrern der zum Tablespace gehrenden Datei

Beides passiert mit Hilfe des Befehls alter database datafile, dem die betriebssystemspezifische Vorgabe des zum Tablespace zugehrigen Dateinamens folgt. Mit Hilfe der Klausel resize knnen Sie die Datei vergrern, indem Sie hinter der Klausel die neue Gre in Kilo- (K) oder Megabyte (M) vorgeben. Durch die Klausel autoextend on wird die automatische Vergrerung der Datei eingeschaltet. Hierbei gibt die Klausel next an, in welcher Schrittgre das passieren soll und die Klausel maxsize legt die maximale Gre der Datei fest, wobei die durch Verwendung von unlimited anschlieend uneingeschrnkt wachsen kann. Hinzufgen einer weiteren Datei Ist beispielsweise auf dem aktuellen Datentrger kein Platz mehr, dann knnen Sie den Tablespace auch dadurch vergrern, dass Sie ihm eine weitere Datei auf einem anderen Datentrger zuweisen.
alter tablespace usr add datafile 'E:\ORANT\DATABASE\DB01\USR2DB01.ORA' size 50K autoextend on next 3K maxsize 200K;
Listing 2.70: Vergrern des Tablespace durch Hinzufgen einer neuen Datei

Dies passiert im Unterschied zu vorhin mit einer alter tablespace-Anweisung. Im Rahmen des Befehls knnen Sie zusammen mit der Klausel add dem Tablespace eine zustzliche Datei zuweisen, wobei Sie mit Hilfe der schon bekannten Parametern die Anfangsgre, sowie bei automatischem Wachstum auch die Schritt- und Maximalgre der Datei vorgeben mssen.

Die Beispieldatenbank anlegen

223

Umzug der Datendateien Wird es insgesamt eng, dann kann vielleicht ein Umzug der einen oder anderen Datei helfen. Das geht allerdings nicht mit einem einzigen Befehl, sondern hierzu bentigen Sie mal wieder einen kleineren Ablauf, bei dem auch Betriebssystemaktivitten notwendig werden. Die prinzipielle Vorgehensweise zum Umzug der zu einem Tablespace gehrenden Dateien ist folgender: 1. Inaktivieren Sie den betreffenden Tablespace. Verwenden Sie hierzu den Zusatz normal, damit alle noch laufenden Transaktionen ordentlich abgeschlossen werden.
alter tablespace usr offline normal;

2. Kopieren bzw. verschieben Sie die betreffenden Dateien an die gewnschten neuen Stellen. Bei Bedarf knnen Sie die Dateien dabei auch umbenennen. In meinem Fall habe ich die Dateien einfach nur umbenannt, da ich eigentlich keinen Anlass fr einen Umzug hatte. 3. ndern Sie die Dateizuordnung in der Tablespacedefinition. Hierzu gibt es eine spezielle Variante des alter tablespace-Befehls.
alter tablespace usr rename datafile 'E:\ORANT\DATABASE\DB01\USR1DB01.ORA', 'E:\ORANT\DATABASE\DB01\USR2DB01.ORA' to 'E:\ORANT\DATABASE\DB01\USR1DB01a.ORA', 'E:\ORANT\DATABASE\DB01\USR2DB01a.ORA';

Mit Hilfe dieser Variante wird die Liste der hinter den Schlsselwrtern rename datafile spezifizierten Dateien gegen die hinter dem Wrtchen to aufgezhlten Dateinamen ausgetauscht. 4. Machen Sie den Tablespace wieder verfgbar, indem Sie ihn in Analogie zum Schritt Nr. 2 wieder einschalten.
alter tablespace usr online;

5. Denken Sie immer daran: Wer sichert, ist feige :-). Der letzte Punkt war natrlich nicht so ernst gemeint. Denken Sie bei solchen Aktionen immer daran, dass Sie quasi am offenen Herzen operieren. Ich wrde mich ohne Netz und doppelten Boden an kein Trapez hngen, Sie etwa? Von daher wrde ich die betroffenen Dateien immer kopieren (statt verschieben) und auch erst dann Lschen, wenn der Tablespace wieder online ist und funktioniert. Noch sicherer ist natrlich das vorherige Herunterfahren der gesamten Datenbank und das anschlieend Backup aller Daten- und Kontrolldateien.

2.3.3

Anlegen des Schemas

Jetzt ist es endlich soweit und wir beginnen damit, die in Abbildung 2.19 dargestellte Struktur unserer kleinen Personaldatenbank anzulegen. Alle gleich folgen-

224

Datenbankobjekte in einer Oracle-DB

den kleinen Skripte finden Sie auf der Begleit-CD in dem \DATEN-Verzeichnis. Dabei entsprechen die Dateinamen den Namen der angelegten Tabellen zuzglich der Endung .SQL (z.B. PERSONALIEN.SQL). Personalien In der Tabelle speichern wir spter unsere Personalstammdaten. Wie Sie der Abbildung 2.19 entnehmen knnen, enthlt sie eine Reihe von Fremdschlsseln, deren berwachung wir allerdings erst zu einem spteren Zeitpunkt mit Hilfe verschiedener Constraints implementieren werden. Die Tabelle erhlt einen Primrschlssel und einen expliziten Index fr das Feld name.
drop table personalien; / create table personalien ( persnr varchar2(11) not null, name varchar2(50) not null, strasse1 varchar2(35), strasse2 varchar2(35), strasse3 varchar2(35), strasse4 varchar2(35), ort varchar2(30), land varchar2(3), bland varchar2(6), plz varchar2(12), telefon varchar2(24), geschlecht varchar2(1) not null, familienstd varchar2(1) not null, familienstd_dt date, gebdatum date not null, gebort varchar2(30), gebland varchar2(3) not null, constraint persnr_pk primary key (persnr) using index tablespace indx storage (initial 100K next 100K) ) tablespace usr storage (initial 100K next 100K ); / create index personalien1 on personalien (name) tablespace indx storage (initial 100K next 100K) / commit;
Listing 2.71: Anlage der Tabelle personalien

Die Beispieldatenbank anlegen

225

Lnder Mit Hilfe der Lndertabelle werden die in den Personalien erfassten Lnderschlssel vertextet. Der Schalter im Feld bland gibt vor, ob es fr das Land in der Tabelle blaender eine weitere Unterteilung (z.B. Bundeslnder) gibt oder nicht. Fr das Feld bland sind nur die Werte Y bzw. N gltig, was mit Hilfe eines entsprechenden check-Constraints geprft wird. Auerdem erhlt die Tabelle wieder einen Primrschlssel.
drop table laender; / create table laender ( land varchar2(3) not null, bland varchar2(1) default 'N' not null , bezeichnung varchar2(30), constraint laender_pk primary key (land) using index tablespace indx storage (initial 10K next 10K), constraint bland_check check (bland in ('Y','N')) ) tablespace usr storage (initial 20K next 20K ); / commit;
Listing 2.72: Anlage der Lndertabelle laender

Bundeslnder Mit Hilfe der jetzt folgenden Tabelle kann eine weitergehende Unterteilung der Lnder in Bundeslnder oder Provinzen durchgefhrt werden. Die Tabelle besitzt als ersten Schlssel das Feld land, der wiederum ein geliehener Schlssel aus der Lndertabelle ist. Der zweite Schlssel kodiert das jeweilige Bundesland und wird in den Personalstammdaten erfasst. Dabei regelt der in der Lndertabelle vorhandene Schalter bland, ob Bundeslnder verfgbar sind bzw. erfasst werden mssen.
drop table blaender; / create table blaender ( land varchar2(3) not null, bland varchar2(6) not null, bezeichnung varchar2(30), constraint blaender_pk primary key (land, bland) using index tablespace indx storage (initial 10K

226

Datenbankobjekte in einer Oracle-DB

next 10K) ) tablespace usr storage (initial 20K next 20K ); / commit;
Listing 2.73: Anlegen der Bundeslnder in der Tabelle blaender

Beschftigungsverhltnisse In unserer Personaldatenbank kann ein Mitarbeiter mehr als ein Beschftigungsverhltnis haben. Solche unterschiedlichen BVs knnen beispielsweise dadurch entstehen, dass ein Mitarbeiter im Laufe seines Lebens mehrfach in einem Unternehmen ein- bzw. austritt. Aber auch die Versetzung in ein anderes Konzernunternehmen fhrt zu einem neuen Beschftigungsverhltnis. Diese BVs hngen direkt an den Personalien und werden mit Hilfe einer laufenden Nummer fortlaufend durchnummeriert. Ansonsten erhlt die Tabelle zunchst einmal zwei Constraints, mit denen der Primrschlssel und eine Werteprfung fr das Feld lfdnr erstellt wird. Beachten Sie auch noch einmal die vorhandenen Verknpfungen zu den Tabellen unternehmen und austrittsgruende ber die entsprechenden Datenfelder. Die Realisierung der hier notwendigen Manahmen zur berwachung der referentiellen Integritt wird uns aufgrund der Historisierung der Referenztabellen im weiteren Verlauf des Buches noch Freude machen.
drop table bvs; / create table bvs ( persnr varchar2(11) not null, lfdnr smallint not null, eintrt date not null, austrt date, ausgrd varchar(3), unternehmen varchar(3) not null, constraint lfdnr_check check (lfdnr >= 0), constraint bvs_pk primary key (persnr, lfdnr) using index tablespace indx storage (initial 10K next 10K) ) tablespace usr storage (initial 20K next 20K ); / commit;
Listing 2.74: Anlage der Beschftigungsverhltnisse

Die Beispieldatenbank anlegen

227

Unternehmen Mit Hilfe der folgenden Tabelle speichern und vertexten wir die verfgbaren Unternehmen. Dabei ist die Tabelle historisch aufgebaut, d.h. pro Unternehmen kann es mehrere Datenstze mit unterschiedlichen gltig-ab-Daten (gab) geben. In dem Zusammenhang ist des Feld status besonders beachtenswert. Selbst ohne echte Historien knnen Sie ein Unternehmen ab einem bestimmten Termin inaktivieren, indem Sie einen neuen Datensatz einfgen und anschlieend im Statusfeld den Wert I (=inaktiv) speichern. Der Wertebereich fr das Statusfeld und der Primrschlssel der Tabelle werden mit Hilfe entsprechender Constraints angelegt.
drop table unternehmen; / create table unternehmen ( unternehmen varchar2(3) not null, gab date not null, status varchar2(1) default 'A' not null, bezeichnung varchar2(30) not null, constraint status_chk check (status in ('A','I')), constraint unternehmen_pk primary key (unternehmen, gab) using index tablespace indx storage (initial 10K next 10K ) ) tablespace usr storage (initial 20K next 20K ); / commit;
Listing 2.75: Erstellen der Unternehmenstabelle

Kostenstellen Mit Hilfe der Kostenstellentabelle werden die Kostenstellen definiert, die selbst wiederum unternehmensbezogen sind, d.h. in unserem Datenmodell besitzt jedes Unternehmen seine eigenen Kostenstellen. Genau wie die Unternehmen, besitzen auch die Kostenstellen ein Historiendatum (gab) und ein Statusfeld, mit dem die Verwendung einer nicht mehr gltigen Kostenstelle ausgeschlossen werden soll. Die Wertebereichsprfung fr den Status und der Primrschlssel der Tabelle werden auch hier wieder mit Hilfe entsprechender Constraints realisiert.
drop table kostenstelle; / create table kostenstelle ( unternehmen varchar2(3) not null, kst varchar2(10) not null, gab date not null,

228

Datenbankobjekte in einer Oracle-DB

status varchar2(1) default 'A' not null, bezeichnung varchar2(30) not null, constraint kst_status_chk check (status in ('A','I')), constraint kostenstelle_pk primary key (unternehmen, kst, gab) using index tablespace indx storage (initial 10K next 10K) ) tablespace usr storage (initial 20K next 20K); / commit;
Listing 2.76: Anlage einer Tabelle zum Speichern der Kostenstellen

Gehlter Von Steuern und Sozialversicherungsabgaben wollen wir nichts wissen, aber wenigstens Gehalt sollen unsere fiktiven Mitarbeiter bekommen. Aus diesem Grund existiert in unserem Schema ein kleiner Gehaltsdatensatz, mit dessen Hilfe wir das Gehalt und die Kostenstelle des Mitarbeiters speichern knnen. Wie im richtigen Leben, so hoffen auch unsere virtuellen Mitarbeiter natrlich auf hufige und entsprechend ppige Gehaltsvernderungen, weshalb die Gehaltstabelle wieder historisch aufgebaut ist. Auerdem hngt sie natrlich nicht direkt an den Personalien, denn das Vorhandensein eines Beschftigungsverhltnisses ist eine Voraussetzung fr jegliche Gehaltszahlung. Ansonsten wird hier nur die Kostenstelle als Fremdschlssel aus der Kostenstellentabelle entliehen. Neben der Erstellung des Primrschlssels finden Sie hier zur Zeit nur zwei weitere Constraints, mit denen die Betrge der beiden Gehaltsfelder berprft werden.
drop table gehalt; / create table gehalt ( persnr varchar2(11) not null, lfdnr smallint not null, gab date not null, kst varchar2(10) not null, gehalt number(9,2) not null, zulage number(9,2) not null, constraint gehalt_ck check (gehalt >= 0), constraint zulage_ck check (zulage >= 0), constraint gehalt_pk primary key (persnr, lfdnr, gab) using index tablespace indx storage (initial 10K next 10K) ) tablespace usr

Die Beispieldatenbank anlegen

229

storage / commit;

(initial 30K next 30K );

Listing 2.77: Erstellen der Gehaltstabelle

Austrittsgrnde Damit kommen wir zunchst einmal zur letzten unserer Stammdatentabellen. Wie Sie wieder der Abbildung 2.19 entnehmen knnen, werden die Austrittsgrnde aus den Beschftigungsverhltnissen heraus referenziert. Die Historisierung der Tabelle wird auch diesmal wieder primr aus der Notwendigkeit getrieben, einen vorhandenen Schlssel ab einem bestimmten Datum zu inaktivieren. Aus dem Grund finden Sie also auch hier wieder die beiden Felder gab und status. Durch die vorhandenen Constraints wird zunchst wieder der Primrschlssel gebildet und es erfolgt die berwachung der im Statusfeld verwendeten Werte.
drop table austrittsgruende; / create table austrittsgruende ( ausgrd varchar2(3) not null, gab date not null, status varchar2(1) default 'A' not null, bezeichnung varchar2(30) not null, constraint aus_status_chk check (status in ('A','I')), constraint austrittsgruende_pk primary key (ausgrd, gab) using index tablespace indx storage (initial 10K next 10K) ) tablespace usr storage (initial 10K next 10K); / commit;
Listing 2.78: Anlegen einer Tabelle zum Speichern der Austrittsgrnde

Nach Anlage dieser letzten Tabelle ist unser Schema zunchst einmal fertiggestellt. Zu einem spteren Zeitpunkt werden wir uns um die Einrichtung der referentiellen Integrittsberwachung kmmern, d.h. am Ende des Kapitels zur PL/SQL-Programmierung finden Sie mgliche Verfahrensweisen hierzu.

230

Datenbankobjekte in einer Oracle-DB

2.4

Datenmigration

Wenn Sie schon einmal an einem greren Umstellungsprojekt mitgearbeitet haben, dann wissen Sie, dass irgendwann der Zeitpunkt kommt, an dem man die grne Entwicklungswiese verlassen muss und wo es darum geht, die Daten aus den Altanwendungen in das neue System zu bertragen. Da es dabei in der Praxis meistens schon um mehr als eine Handvoll von Datenstzen geht, ist es schon ein interessanter Aspekt, sich einmal anzuschauen, welche Hilfsmittel und Mglichkeiten Oracle hierbei bietet. Normalerweise werden die alten Daten nicht deckungsgleich in die neue Struktur passen, d.h. Sie haben es im Wesentlichen mit den drei folgenden Problemen zu tun:

Die Daten sind im neuen System anders strukturiert. Dabei gibt es nicht nur neue und andere Schlsselbegriffe, sondern auch die Stammdaten werden im neuen System vielleicht anders gruppiert, bestimmte Informationen (z.B. Historien) werden anders dargestellt. Die bentigten Daten mssen blicherweise zunchst aus den Altsystemen bereitgestellt bzw. exportiert werden, wobei wir einfach mal davon ausgehen, dass es sich hierbei nicht um eine Oracle-Datenbank handelt. Manchmal mssen alle bentigten Informationen sogar aus verschiedenen Quellen eingesammelt werden. Letztendlich existiert dann auch noch ein Importproblem, denn die aus den Altsystemen erhaltenen Daten kommen schlielich nicht von alleine in die neue Datenbank.

Gerade der zuerst genannte Punkt wrzt das insgesamt vorhandene Problem ganz pikant, denn wir haben es hier nicht nur mit einer rein technischen Aufgabenstellung zu tun, sondern bentigen whrend der Migration eine Menge von Ablauflogik, um die gelesenen Daten umzuformatieren, zu mischen oder entsprechend der neuen Struktur zu speichern. Welche Mglichkeiten Sie in Bezug auf den Export der Daten haben, das hngt natrlich wesentlich von dem konkret vorliegenden Altsystem ab. In unserem Beispiel geht es auch weniger darum, wie die Daten aus dem Altsystem kommen, sondern es interessiert vornehmlich die Frage, wie diese Daten aussehen sollten, damit sie besonders einfach in eine Oracle-Datenbank importiert werden knnen. Insgesamt denke ich, erhalten Sie im weiteren Verlauf dieses Kapitels viele Informationen und Anregungen, auf welche Art und Weise Sie eine solche Migrationsaufgabe anpacken knnen.

2.4.1

Variationsmglichkeiten

Es gibt bekanntlich viele Wege nach Rom. Alle diese Wege unterscheiden sich, allerdings nicht immer unbedingt in gut oder schlecht bzw. lang oder kurz. So gibt es auch hier mal wieder kein Patentrezept, kein schwarz oder wei in Bezug auf den optimalen Lsungsweg Ihre Oracle-Datenbank mit Altdaten zu versorgen. Nach

Datenmigration

231

meiner Erfahrung, und die ist was Migrationsaufgaben angeht schon ganz beachtlich, schadet es nicht, wenn Sie in Ihrem Konzept ber die nachfolgende Aspekte zumindest einmal nachdenken.

Artenreichtum lsst das Herz eines jeden Botanikers hher schlagen. Bei Migrationsaufgaben sollte man die Anzahl der Varianten eher gering halten. Wenn Sie hunderte von Tabellen migrieren und dabei fr jede zweite Tabelle ein neues Verfahren erfinden, dann ist die Aufgabenstellung irgendwann nur noch von Ihnen selbst durchfhrbar und mich wrde es nicht wundern, wenn in Folge der Hektik des Tages x selbst Ihnen Fehler unterlaufen. Vermeiden Sie Mischformen. Wie schon angedeutet, bentigt man im Rahmen des Datentransports hufig eine gewisse Ablauflogik. Nach meiner Erfahrung hat es sich bewhrt, wenn man sich dabei entscheidet, diese Logik entweder im Ziel oder in der Quelle zu realisieren und diese selbstauferlegte Restriktion auch weitestgehend einzuhalten. Als Konsequenz dieses Handelns ist eine der beiden beteiligten Schnittstellen dann meistens sehr einfach aufgebaut. Liegen die Daten beispielsweise aufgrund komplexer Exportprogramme genau in der bentigten Form vor, dann knnen Sie diese mit Hilfe von Standardtools in die Datenbank einspielen. Umgekehrt knnen Sie die Daten vielleicht mit Hilfe von vorhandenen Utilities exportieren, wenn Sie die bentigten Importfunktionalitten im neuen System geplant haben (vgl. Abb. 2.20). Migration ist kein Einmalgeschft. Sicherlich spielen die durchgefhrten Importaktivitten nach dem Projektende keine groe Rolle mehr und trotzdem sollten Sie sich vom dem Gedanken des einmaligen Verwendungszwecks nicht zu allzu abenteuerlichen Verfahrensweisen, womglich mit vielen manuellen Eingriffen, verleiten lassen. Meistens stellt sich whrend des Projekts nmlich heraus, dass die Migrationsaktiviten zumindest bis zum Projektende aufgrund verschiedener Testdatenbanken, eventueller Vorabpilotierung bestimmter Anwendungsteile doch regelmiger als zunchst geplant eingesetzt werden. Bercksichtigen Sie von vornherein das zu erwartende Mengengerst. Mit zehn Datenstzen klappt jedes denkbare Verfahren. Bei mehren Millionen Datenstzen sieht das ganz anders aus. Selbst bei ein paar tausend Datenstzen wrde ich nach meiner Erfahrung davon abraten ein Verfahren zu konstruieren, das stark von der Existenz einer vorhandenen Netzwerkverbindung abhngt. Verlagern Sie das gesamte Migrationsgeschft mglichst direkt auf die Server, d.h. verwenden oder schreiben Sie nur Programme, die direkt auf den Datenbankservern lauffhig sind. Ebenso sollten Sie von vornherein Mechanismen vorsehen, die es Ihnen ermglichen, abgebrochene Migrationsjobs wieder aufzusetzen und das gesamte bernahmeverfahren sollte mglichst modular aufgebaut werden, damit im Fehlerfall nicht immer nur alle sondern auch einzelne Tabellen neu aufgebaut werden knnen. berlegen Sie sich, ob Sie den Datenimport mit oder ohne aktivierte Prfroutinen, egal ob in der Form spezieller Constraints oder ber Triggerprogramme, durchfhren wollen. Ohne diese Prfroutinen geht das Laden der Daten sicherlich schneller, allerdings sollten Sie in dem Fall auch schon gewissen Konsis-

232

Datenbankobjekte in einer Oracle-DB

tenzprfungen in den Importprogrammen vorsehen. Manchmal hat man aber auch gar keine Wahl fr die eine oder andere Variante, beispielsweise dann, wenn aufgrund komplexer Abhngigkeiten quasi alle Daten in einem logischen Schritt geladen werden mssten.

Quelle

Exportprogramm(e)

Export-Utilitie

Exportdateien

Import

Import-Utilitie
Abfragen, SQL-Programme

Ziel

Abbildung 2.20: Gegenberstellung zweier gngiger Migrationsvarianten

Die Abbildung 2.20 verdeutlicht den beschriebenen Zusammenhang der Mischformen noch einmal. Entsprechend der links dargestellten Verfahrensweise wurden die bentigten Daten mit Hilfe komplexer Exportprogramme gem der neuen Datenbankstruktur aufbereitet. Aus diesem Grund knnen die Exportdateien mit Hilfe eines Oracle-Ladetools direkt in die neuen Zieltabellen importiert werden, d.h. im Ziel findet keine Aufbereitungslogik der Daten mehr statt. Im Gegensatz dazu werden die Daten im rechten Teil der Abbildung 2.20 mit Hilfe eines Exporttools oder zumindest sehr einfacher Programme aus dem Quellsystem ausgegeben. Anschlieend werden die Daten wieder mit Hilfe eines Oracle-Werkzeugs in entsprechende Arbeitstabellen geladen, von wo aus sie mit Hilfe entsprechender Abfragen oder PL/SQL-Programme in die jeweiligen Zieltabellen verteilt werden. Alternativ hierzu wren auch noch spezielle Importprogramme denkbar, die die einzelnen Importdateien verarbeiten und dabei die neuen Zieltabellen direkt beschreiben. Allerdings sollte man in dem Fall darauf achten, dass hierbei nur Programme eingesetzt werden, die direkt auf dem Datenbankserver lauffhig sind.

Datenmigration

233

Ich persnlich wrde meistens den im rechten Teil der Abbildung skizzierten Weg bevorzugen. Das liegt zum einen schon an der von mir geforderten Einschrnkung an Varianten, denn in der Praxis existiert in greren Projekten mehr als eine Datenquelle mit einer Bandbreite von der Mainframe-IMS-Datenbank bis hin zum manuell erstelltem Excel-Spreadsheet. In dem Fall haben Sie eigentlich gar keine Chance, die Daten mit Hilfe der Exportprogramme fertig aufzubereiten. Zum anderen liegt es sicherlich auch an den Quellen selbst, die oft nur mit Hilfe schwerflliger Programme oder anflligen Makros abgefragt werden knnen. Sind die Daten aber erst einmal in der Oracle-Datenbank angekommen, dann steht Ihnen mit SQL bzw. PL/ SQL ein nahezu unerschpfliches Repertoire an Mglichkeiten zur Verfgung.

2.4.2

Laden unserer Beispiel-DB

Nach diesen allgemeinen Vorbemerkungen wollen wir uns nun wieder unserer kleinen Personaldatenbank widmen und damit beginnen, sie mit Daten zu fllen. Dabei entspricht die von uns verwendete Methode dem linken Teil der Abbildung 2.20, d.h. die zu importierenden Daten liegen in einer dem Ziel entsprechenden Form vor, und obwohl ich vorhin gesagt habe, dass es so etwas im richtigen Leben eigentlich gar nicht gibt, so ist es fr uns dennoch interessant, weil es uns hier vornehmlich darauf ankommt, zu schauen, wie die Daten mit Hilfe von Oracle-Tools oder anderen Methoden geladen werden knnen. Austrittsgrnde Fr kleine Tabellen kann es sinnvolle Variante sein, den Importvorgang mit Hilfe eines SQL-Skripts durchzufhren. In dem Fall mssen Sie die zu importierenden Daten in entsprechende insert-Anweisungen verpacken. Die Daten der Austrittsgrnde finden Sie auf der Begleit-CD in der Datei \DATEN\AUSTRITTSGRUENDE.TXT und das Importskript heit IMP_AUSTRITTSGRUENDE.SQL. Ursprnglich stammen Sie aus der vorhandenen Access-Datenbank und wurden mit Hilfe der dort vorhandenen Abfrage export austrittsgruende als Datei mit fester Satzlnge exportiert.
insert into austrittsgruende (ausgrd, gab, status, bezeichnung) to_date('01.01.1990','DD.MM.YYYY'),'A','Kndigung AN'); insert into austrittsgruende (ausgrd, gab, status, bezeichnung) to_date('01.01.1990','DD.MM.YYYY'),'A','Kndigung AG'); insert into austrittsgruende (ausgrd, gab, status, bezeichnung) to_date('01.01.1990','DD.MM.YYYY'),'A','Versetzung'); insert into austrittsgruende (ausgrd, gab, status, bezeichnung) values ('55', values ('56', values ('60', values

Wir betten diese Textdatei in folgende Anweisungsfolge ein, mit der zum einen die Tabelle vorab gelscht und am Ende die ganze Transaktion mit einem commitBefehl abgeschlossen wird.
truncate table austrittsgruende; @c:\temp\austrittsgruende.txt; commit;
Listing 2.79: Einspielen der Austrittsgrnde (IMP_AUSTRITTSGRUENDE.SQL)

234

Datenbankobjekte in einer Oracle-DB

Wenn Sie sich nun fragen, warum ich das so kompliziert mache, und die truncatebzw. commit-Befehle nicht einfach mit in die Textdatei schreibe, dann kann ich darauf nur entgegnen, dass ich mich ja wenigstens in diesem Buch an meine eigenen Regeln halten will, denn durch diese Trennung wird der gesamte Prozess ohne manuelle Eingriffe wiederholbar. Einfach die Austrittsgrnde neu exportieren und danach das Importskript erneut starten. Lnder Die Lndertabelle importieren wir genau wie die Austrittsgrnde. Die zugehrigen Daten finden Sie wieder in Form von insert-Anweisungen in der Datei \DATEN\LAENDER.TXT; das Importskript befindet sich in der Datei IMP_LAENDER.SQL. Die Datendatei wurde aus der Access-Datenbank mit Hilfe der Abfrage export laender erstellt.
insert insert insert insert insert insert into into into into into into laender laender laender laender laender laender (land, (land, (land, (land, (land, (land, bland, bland, bland, bland, bland, bland, bezeichnung) bezeichnung) bezeichnung) bezeichnung) bezeichnung) bezeichnung) values values values values values values ('DEU','Y','Deutschland'); ('AUT','Y','sterreich'); ('BEL','N','Belgien'); ('GBR','N','Grossbritannien'); ('FIN','N','Finnland'); ('FRA','N','Frankreich');

Die Datei knnen Sie folgendermaen einspielen:


truncate table laender; @c:\temp\laender.txt; commit;
Listing 2.80: Einspielen der Lndertabelle (IMP_LAENDER.SQL)

Bundeslnder Genau wie bisher gehen wir auch bei den Bundeslndern vor. Die zum Importieren bentigten insert-Anweisungen und das Importskript finden Sie in den Dateien BLAENDER.TXT bzw. IMP_BLAENDER.SQL. Die Datendatei wurde aus der AccessDatenbank mit Hilfe der Abfrage export blaender erstellt.
insert len'); insert insert insert into blaender (land, bland, bezeichnung) values ('DEU','NW','Nordrhein-Wesfahinto blaender (land, bland, bezeichnung) values ('DEU','BY','Bayern'); into blaender (land, bland, bezeichnung) values ('DEU','BE','Berlin'); into blaender (land, bland, bezeichnung) values ('DEU','HH','Hamburg');

Die Datei spielen Sie wieder mit Hilfe folgender Anweisungen in die Datenbank ein:
truncate table blaender; @c:\temp\blaender.txt; commit;
Listing 2.81: Importieren der Bundeslnder (IMP_BLAENDER.SQL)

Datenmigration

235

Unternehmen Die nchste kleine Referenztabelle enthlt die Unternehmen unserer Datenbank und wird mit Hilfe der Dateien UNTERNEHMEN.TXT bzw. IMP_UNTERNEHMEN.SQL importiert. Die Daten stammen ebenfalls aus der Access-Datenbank und wurden mit Hilfe der dortigen Abfrage export unternehmen erstellt.
insert into unternehmen (unternehmen, gab, status, bezeichnung) values to_date('01.01.1990','DD.MM.YYYY'),'A','Raymans EDV Beratung'); insert into unternehmen (unternehmen, gab, status, bezeichnung) values to_date('01.01.1998','DD.MM.YYYY'),'A','Raymans Medienberatung'); insert into unternehmen (unternehmen, gab, status, bezeichnung) values to_date('01.11.2001','DD.MM.YYYY'),'I','Raymans Medienberatung'); insert into unternehmen (unternehmen, gab, status, bezeichnung) values to_date('01.01.1992','DD.MM.YYYY'),'A','Raymans Consulting GmbH'); ('001', ('002', ('002', ('001',

Das Einspielen der Unternehmensdaten erfolgt in der mittlerweile gewohnten Weise:


truncate table unternehmen; @c:\temp\unternehmen.txt; commit;
Listing 2.82: Einspielen der Unternehmen (IMP_UNTERNEHMEN.SQL)

Kostenstellen Die letzte unserer Referenztabellen enthlt die Kostenstellen und da das ganze Verfahren mittlerweile langweilig wurde, habe ich hier einmal das Hinzufgen manuell erfasster Kostenstellen simuliert. Zum einen finden Sie daher die Datei KOSTENSTELLEN.TXT, deren Inhalt mit Hilfe der Abfrage export kostenstellen aus der Access-Datenbank exportiert wurde. Zum anderen enthlt Ihre CD aber noch eine zweite Datei mit dem treffenden Namen MANUELLE_KST.TXT, die eine selbsterfasste Kostenstelle enthlt. Das zum Import verwendete Skript finden Sie in der Datei IMP_KOSTENSTELLEN.SQL.
insert into kostenstelle (unternehmen, kst, gab, status, bezeichnung) values ('001','PSOFT', to_date('01.01.1992','DD.MM.YYYY'),'A','PeopleSoft-Beratung'); insert into kostenstelle (unternehmen, kst, gab, status, bezeichnung) values ('001','PERS', to_date('01.01.1990','DD.MM.YYYY'),'A','Personalabteilung'); insert into kostenstelle (unternehmen, kst, gab, status, bezeichnung) values ('002','MARK', to_date('01.01.1998','DD.MM.YYYY'),'A','Marketing');

Das folgende Skript zum Einspielen der Kostenstellen bindet ausnahmsweise einmal zwei Datendateien ein.
truncate table kostenstellen; @c:\temp\kostenstellen.txt; @c:\temp\manuelle_kst.txt; commit;
Listing 2.83: Einspielen der exportierten und manuell erfassten Kostenstellen

236

Datenbankobjekte in einer Oracle-DB

2.4.3

Der Data Manager

Eigentlich alle aktuellen Datenbanksystem liefern ein Werkzeug, um sequentielle Dateien (sogenannte Flatfiles) zu importieren. Der Vorteil dieser Programme besteht dabei im Unterschied zu allen anderen denkbaren Alternativen eigentlich immer in der rasanten Arbeitsgeschwindigkeit, mit der die importierten Daten in die Zieltabellen geschrieben werden. Bei Oracle ist so ein Werkzeug natrlich auch vorhanden. Es handelt sich hierbei um den sogenannten Data Manager, mit dem allerdings nicht nur die hier bentigten Importaufgaben erledigt werden knnen. Bei dem Data Manager handelt es sich um ein Programm, mit dem Sie zum einen einzelne Tabellen bis hin zu ganzen Datenbanken exportieren und auch wieder einspielen knnen. Damit eignet sich dieses Werkzeug beispielsweise zum Sichern einzelner Tabellen oder ermglicht auch den Umzug einer ganzen Datenbank beispielsweise in eine neue Rechnerumgebung. Zum anderen knnen Sie das Programm auch zum Importieren von gewhnlichen Textdateien verwenden. hnlich wie bei SQL*Plus besitzen auch die zum Data Manger gehrenden Programme die Eigenschaft, dass sie sowohl auf allen denkbaren Plattformen zu Hause sind, als auch, dass sie berall gleich bedient werden. Fr den NT-Client bietet Oracle allerdings mal wieder eine Luxusversion an, und hat den drei genannten Funktionen (Export, Import, Laden) eine bliche Windows-Oberflche bergestlpt. Bei der 8er-Version finden Sie das Programm-Icon fr diese Oberflche normalerweise in der Programmgruppe Oracle Enterprise Manager; ansonsten knnen Sie auch das zugehrige Programm VAD.EXE direkt aufrufen. Bei der 8i-Version erhalten Sie den Zugang zu dem Programm mit Hilfe des Werkzeuge-Mens. Folgen Sie dort dem Eintrag Datenverwaltung und anschlieend dem Men Laden, um zu den entsprechenden Ladeassistenten zu gelangen. Die wesentlichen Bestandteile des Programms finden Sie im Data-Men. Dort verzweigen Sie mit Hilfe der Eintrge Export, Import und Load in jeweils unterschiedliche Assistenten (vgl. Abb. 2.22), die alle notwendigen Eingaben und Parameter abfragen, um anschlieend das eigentliche Programm zu starten oder einen entsprechenden Job innerhalb der Datenbank zu triggern. Letzteres funktioniert natrlich nur dann, wenn das zugehrige System zur Jobsteuerung auf Ihrem Datenbankserver aktiviert wurde. Wie schon gesagt, bentigen wir in unserem Fall zum Laden der brigen Tabellen unserer Personaldatenbank die Ladefunktion (SQL*Loader) des Data Managers. Konkret verbirgt sich dahinter unter NT das Programm SQLLDR80.EXE bzw. SQLLDR.EXE bei der 8i-Version (bzw. einfach nur SQLLDR, z.B. unter AIX). In jedem Fall sollten Sie darauf achten, dass Sie das Programm auf dem Datenbankserver starten, damit seine rasante Arbeitsgeschwindigkeit voll zur Geltung kommt und nicht durch ein eventuelle lahmes Netzwerk ausgebremst wird.

Datenmigration

237

Abbildung 2.21: NT-Oberflche des Data Managers in der 8er-Version

Abbildung 2.22: Assistent zum Abfragen der bentigten Ladeparameter

238

Datenbankobjekte in einer Oracle-DB

Starten des SQL*Loaders Das Programm erwartet beim Aufruf eine Reihe von Kommandozeilenparametern, die zum Teil allerdings auch in einer sogenannten Kontroll- bzw. Steuerungsdatei, die ebenfalls Teil der Kommandozeilenparameter ist, verwendet werden knnen. Bei dem Verwenden von Parametern mssen Sie entweder eine strikte Reihenfolge beachten, oder die einzelnen Parameterwerte mit Hilfe eines Schlsselworts in der Form <Schlssel>=<Wert> bergeben. Da ich es praktischer finde, die Steuerung des Ladeprogramms mit Hilfe einer Parameterdatei durchzufhren, finden Sie die Erluterung der aus meiner Sicht wichtigsten drei Parameter in der folgenden Tabelle 2.5.

Parameter USERID

Beschreibung bergeben Sie mit Hilfe dieses Schlssels eine gltige Verbindungszeichenfolge in der blichen Form <Benutzer-Id>/<Passwort>@<Servicename> (z.B.system/ manager@db01). Den Servicenamen mssen Sie natrlich weglassen, wenn Sie beim Laden die direkte Methode verwenden. Verwenden Sie den Parameter, um mit ihm den Namen und Pfad der Steuerdatei zu spezifizieren. Auf den Aufbau dieser Steuerdatei werde ich spter noch zurckkommen; kurz zusammengefasst enthlt die Steuerdatei den Namen und den Aufbau der Importdatei. Diesen Parameter mssen Sie nur zusammen mit dem Wert TRUE verwenden, d.h. ansonsten knnen Sie ihn weglassen, so dass das Ladeprogramm von FALSE ausgeht. Was beim direkten Laden genau passiert, das knnen Sie ein paar Zeilen weiter erfahren.

CONTROL

DIRECT

Tabelle 2.5: Tabelle 2.5: Wichtige Parameter fr den Aufruf des SQL*Loaders

Direktes Laden Bezglich der Option des direkten Ladens (DIRECT=TRUE) findet man in manchen Handbchern schon manchmal mystisch anmutende Erklrungen. Ich will einmal versuchen das was eigentlich dahinter steckt, mit einfachen Worten auf den Punkt zu bringen. Bei dieser Methode umgeht Oracle im Prinzip seine internen Strukturen und schreibt die Daten quasi direkt in die zugehrige Tabelle der Datenbank. Eigentlich logisch, dass dies in einer unglaublichen Arbeitsgeschwindigkeit mndet. Aber auch das gibt es mal wieder nicht umsonst, sondern schlgt sich in folgenden Restriktionen nieder.

Keine Ausfhrung von in der Datenbank verankerter Logik. Konkret heit das, dass konsitenzberwachende Regelwerke, beispielsweise in der Form von definierten Constraints oder Triggern nicht beachtet bzw. ausgefhrt werden. Die zu ladenden Daten mssen also in jeglicher Hinsicht in Ordnung sein oder die notwendigen Prfungen mssen spter in einem zweiten, separaten Schritt erfolgen. Die Methode funktioniert nur dann, wenn Sie bei der Ausfhrung des SQL*Loaders das NET8-Protokoll umgehen knnen. Letzteres ist in der Regel nur mglich, wenn das Programm direkt auf dem Datenbankserver ausgefhrt wird.

Das direkte Laden eignet sich damit vor allem zum Laden von Arbeitstabellen zum Beispiel im Rahmen einer Schnittstelle oder beim erstmaligen Aufbau der Daten-

Datenmigration

239

bank. Weitere Informationen zum Gebrauch dieses Werkzeugs finden Sie im nchsten Kapitel, in dem wir mit dem Aufladen unserer Beispieldatenbank fortfahren und hierzu den SQL*Loader einsetzen. Ansonsten hlt auch die Oracle-Dokumentation eine umfangreiche Beschreibung des Werkzeugs bereit. Folgen Sie einfach dem Link Oracle8 Utilities, um zur zugehrigen Dokumentation zu finden.

2.4.4

Laden der Stammdaten per SQL*Loader

Im letzten Abschnitt des zweiten Kapitels wollen wir nun das Aufladen unserer Personaldatenbank fortsetzen, indem wir die Stammdaten mit Hilfe des gerade vorgestellten Ladetools von Oracle importieren. Hierbei werden Sie verschiedene Verfahrensweisen kennen lernen, um auf einen eventuell unterschiedlichen Aufbau der Importdateien reagieren zu knnen. Feste Satzlnge Ein oftmals verwendetes Format bei der Bereitstellung von Exportdateien ist die Verwendung fester Satz- und Feldlngen. Gerade im Grorechnerbereich ist dieses Format hufig anzutreffen, da es in den dort blichen Programmen so leicht zu verwenden ist. Fr unsere kleine Datenbank wollen wir die Personalstammdaten mit Hilfe einer Datei mit fester Satzlnge importieren. Hierzu finden Sie auf der CD die Datei \DATEN\PERSONALIEN.TXT, die per Export aus der in der Access-Datenbank vorliegenden Tabelle gewonnen wurde.

Abbildung 2.23: ffnen der Personalstamm-Textdatei mit Hilfe eines Editors

240

Datenbankobjekte in einer Oracle-DB

Wie Sie der Abbildung 2.23 entnehmen knnen, habe ich der exportierten Textdatei anschlieend vier Zeilen vorangestellt, um mir das Zhlen der Stellen zu vereinfachen. In den ersten drei Zeilen habe ich eine Art Lineal eingefgt und mit Hilfe der vierten Zeile haben ich die einzelnen Felder mit ihrer maximalen Lnge angezeichnet. Diese vier Zeilen drfen natrlich nicht importiert werden, was Sie im Rahmen der Steuerdatei fr den Loader entsprechend einstellen knnen. Bei dieser Steuerdatei handelt es sich ebenfalls um eine gewhnliche Textdatei, die Sie mit jedem beliebigen Editor erstellen knnen. Im Listing 2.84 finden Sie einen Abdruck der zum Laden der Personalien bentigten Steuerdatei, die Sie auf der CD ebenfalls im \DATEN-Verzeichnis unter dem Namen PERSONALIEN.CTL finden.
-- Laden der Personalien options ( skip=4 ) load infile badfile discardfile discardmax truncate into table ( persnr name strasse1 strasse2 strasse3 strasse4 ort land bland plz telefon geschlecht familienstd familienstd_dt gebdatum gebort gebland )
Listing 2.84: Steuerdatei zum Importieren der Personalien

'c:\temp\personalien.txt' 'c:\temp\personalien.bad' 'c:\temp\personalien.dsc' 999 ubeispiel.personalien

position(01:11) position(12:61) position(62:96) position(97:131) position(132:166) position(167:201) position(202:231) position(232:234) position(235:240) position(241:252) position(253:276) position(277:277) position(278:278) position(279:288)

char, char, char, char, char, char, char, char, char, char, char, char, char, date "DD.MM.YYYY" nullif familienstd_dt=blanks, position(298:307) date "DD.MM.YYYY", position(317:346) char, position(347:349) char

Datenmigration

241

Wie Sie dem Listing 2.84 entnehmen knnen, erfolgt die Erfassung der fr den Ladevorgang bentigten Steuerdatei in freier Form. In unserem konkreten Beispiel erstellen wir hierbei die beiden Abschnitte options und load. Mit Hilfe des ersten Abschnittes (options) knnen Sie verschiedene Parameter festlegen, die im Bedarfsfalle auch per Kommandozeilenparameter festgelegt werden knnen. Entnehmen Sie der Tabelle 2.6 die Bedeutung der wichtigsten Optionen.
Option skip load errors direct Standardwert 0 Alle 50 FALSE Beschreibung Anzahl der Zeilen, die vom Loader aus der Datendatei berlesen werden. Anzahl der zu importierenden Datenstze. Maximal erlaubte Fehler, bevor das Programm abbricht. Schaltet bei Bedarf den direkten Ladevorgang ein.

Tabelle 2.6: Wichtige Optionen innerhalb der Steuerdatei des SQL*Loaders

Die einzelnen Optionen werden hinter dem Schlsselwort options in Klammern einfach untereinander aufgezhlt und fr jede verwendete Option schreiben Sie den bentigten Wert mit Hilfe eines Gleichheitszeichens direkt hinter den jeweiligen Optionsschlssel. Die Verwendung irgendwelcher Optionen in der Steuerdatei verhindert im brigen nicht deren berschreibung mit Hilfe eines entsprechenden Kommandozeilenparameters. In unserem Beispiel wrde also der folgende Programmaufruf
sqlldr80 userid=ubeispiel ... skip = 20 sqlldr userid=ubeispiel ... skip = 20

zum berlesen von 20 anstatt der standardmig eingestellten vier Datenstze fhren. Der zweite und wichtigere Abschnitt load enthlt alle bentigten Dateinamen und auch den Aufbau der Importdatei. Dabei folgen zunchst eine Reihe von Anweisungen, mit denen beispielsweise der Name und Pfad der Importdatei, die zu verwendende Datenbanktabelle und weitere gleich nher beschriebene Optionen festgelegt werden knnen. Anschlieend folgt in Klammern der Aufbau der Importdatei, in dem bei einer festen Satzlnge alle Tabellenfelder den entsprechenden Satzpositionen zugeordnet werden.
Parameter infile Beschreibung Pfad und Name der Importdatei. Befinden sich die zu importierenden Daten ebenfalls in der Kontrolldatei, dann mssen Sie fr den Parameter infile den Wert * verwenden, wobei die zu importierenden Daten dem Schlsselwort begindata folgen mssen. Hier knnen Sie eine Datei spezifizieren, in die das Programm alle fehlerhaften Datenstze (z.B. Formatfehler) kopiert. Mit Hilfe dieses Parameters knnen Sie eine Datei vorgeben, in die das Programm alle Datenstze kopiert, deren Einfgeoperation beispielsweise wegen einer Regelverletzung abgewiesen wurde.

badfile discardfile

242

Datenbankobjekte in einer Oracle-DB

Parameter discardmax truncate

Beschreibung Anzahl der zulssigen Abweisungen. Die berschreitung fhrt zu einem Programmabbruch. Verwenden Sie dieses Schlsselwort, wenn die Tabelle vor dem Importieren gelscht werden soll. Ohne diesen Parameter werden die importierten Daten an die Tabelle angefgt. Geben Sie hier den Namen der aufnehmenden Tabelle an.

into table

Tabelle 2.7: Wichtige Ladeparameter

Nach Vorgabe aller bentigten Ladeparameter erfolgt die Definition der zu importierenden Daten. Bei einer festen Satzlnge mssen Sie hierbei jedem Tabellenfeld die entsprechende Satzposition zuweisen, was mit Hilfe des Schlsselworts position passiert, hinter dem die Anfangs- und Endeposition im Datensatz in Klammern eingetragen wird. Danach folgt die Festlegung des Datentyps, wobei Sie vor allem bei Datumsfeldern das im Datensatz verwendete Format festlegen mssen. Beachten Sie hierbei auch die Klausel
nullif familienstd_dt=blanks

die Ihnen ermglicht, bei leeren Feldern in der Datenbank den Wert null zu speichern. Damit htten wir alle notwendigen Definitionen durchgefhrt und es bleibt nur noch brig, das Ladeprogramm zu starten und damit die Personalstammdaten zu importieren. ffnen Sie hierzu ein MS-DOS-Fenster und stellen Sie die Umgebungsvariable oracle_sid auf die zu verwendende Datenbankinstanz ein. Anschlieend knnen Sie den SQL*Loader starten, wobei Sie als Kommandozeilen wenigstens die Anmeldeinformationen und die zu verwendende Steuerdatei bergeben mssen.
set oracle_sid=db01 sqlldr80 userid=ubeispiel/manager control=c:\temp\personalien.ctl direct=true log=c:\temp\personalien.log
Listing 2.85: Starten des SQL*Loaders zum Importieren der Personalstammdaten

In dem Beispiel finden Sie als letzten Parameter einen Wert, der mit Hilfe des Schlssels log bergeben wird, und mit dem Sie den Namen und das Ziel des erstellten Ladeprotokolls festlegen knnen. Als Alternative zur Vorgabe so vieler einzelner Kommandozeilenparameter knnen Sie diese auch in einer sogenannten Parameterdatei zusammenfassen und anschlieend nur die Parameterdatei als Kommandozeilenparameter verwenden.
set oracle_sid=db01 sqlldr80 parfile=personalien.par

Innerhalb dieser Parameterdatei knnen Sie anschlieend alle bentigten Kommandozeilenparameter spezifizieren, was vor allem dann Sinn macht, wenn der Ladevorgang mehrfach oder sogar regelmig wiederholt wird.

Datenmigration

243

userid=ubeispiel/manger control= c:\temp\personalien.ctl direct=true log=c:\temp\personalien.log

Variable Satzlnge Dieses Format geht sparsamer mit dem fr die Exportdatei bentigten Plattenplatz um, in dem fr jedes Feld nur der bentigte Platz im Datensatz verwendet wird. Damit ein solcher Datensatz im Nachhinein wieder in die einzelnen Felder zerlegt werden kann, werden diese im Satz mit Hilfe eines speziellen Trennzeichens verbunden. Auerdem ist es blich, Zeichenketten zustzlich in Anfhrungszeichen zu setzen, da ja zumindest theoretisch die Mglichkeit besteht, dass das Trennzeichen selbst auch in der Zeichenkette auftaucht.
"mit mir nicht; na ja"; 333; 23.11.1998

Datenstze mit variabler Satzlnge knnen heutzutage eigentlich mit jeder gngigen Standardsoftware erstellt und direkt mit Hilfe des SQL*Loaders geladen werden. In unserem Beispiel liegen die Gehaltsdaten (Datei: GEHALT.TXT) in diesem Format vor. Die Daten wurden aus der Access-Datenbank mit Hilfe der Exportspezifikation Gehalt erstellt und haben folgenden Aufbau:
"PERSNR";"LFDNR";"GAB";"KST";"GEHALT";"ZULAGE" "7000001";0;01.01.1990 00:00:00;"PERS";4500.00;500.00 "7000002";0;01.04.1998 00:00:00;"PERS";4750.00;300.00 "7000002";0;01.04.1999 00:00:00;"PERS";4980.00;290.00 "7000003";0;01.08.1999 00:00:00;"EDV";6500.00;0.00

Diesmal wurde die erste Datenzeile mit den Feldnamen beim Export automatisch hinzugefgt. Bei vielen Programmen knnen Sie beim Export explizit vorgeben, ob die erste Datenzeile die Feldnamen enthalten soll oder nicht. Genau wie beim Laden der Personalstammdaten bentigen wir natrlich wieder eine Steuerdatei, die fr den SQL*Loader den Satzaufbau beschreibt.
-- Laden der Gehlter options ( skip=1 ) load infile 'c:\temp\gehalt.txt' badfile 'c:\temp\gehalt.bad' discardfile 'c:\temp\gehalt.dsc' discardmax 999 truncate into table ubeispiel.gehalt fields terminated by ';' optionally enclosed by '"' (

244

Datenbankobjekte in einer Oracle-DB

persnr lfdnr gab kst gehalt zulage )

position(*) position(*) position(*) position(*) position(*) position(*)

char, integer external, date "DD.MM.YYYY HH24:MI:SS", char, decimal external, decimal external

Listing 2.86: Steuerdatei zum Importieren der variabel langen Gehaltsdatenstze

Die Steuerdatei finden Sie auf Ihrem Datentrger unter dem Namen GEHALT.CTL. Eigentlich hat sich im Unterschied zu vorhin gar nicht soviel gendert. Zunchst einmal berlesen wir mit Hilfe der skip-Klausel nur noch den ersten Datensatz, der die Feldnamen enthlt. Des weiteren sind im load-Abschnitt zwei weitere Optionen hinzugekommen, mit denen wir ber die Anweisungen fields terminated by das Feldtrennzeichen und optionally enclosed by das die Textfelder umschlieende Sonderzeichen festlegen. Die Definition des Datensatzes erfolgt fr die einzelnen Felder jetzt natrlich ohne eine feste Positionsangabe. Der als Platzhalter verwendete Stern fhrt innerhalb des Programms immer zur Verwendung des nchsten Feldes. Gestartet wird das Programm natrlich genau wie bei der festen Satzlnge, d.h. es wird lediglich eine andere Steuerdatei als Kommandozeilenparameter bergeben.
set oracle_sid=db01 sqlldr80 userid=ubeispiel/manager control=c:\temp\gehalt.ctl direct=true log=c:\temp\gehalt.log
Listing 2.87: Starten des Imports der Gehaltsdatenstze

Logische Datenstze Mit Hilfe der beiden vorhergehenden Abschnitte haben Sie sicherlich die wichtigsten Verwendungsformen des SQL*Loaders kennen gelernt. Allerdings fehlt uns noch eine Datei zur Vervollstndigung unserer Personaldatenstruktur, und so habe ich mir fr die noch fehlenden Beschftigungsverhltnisse ein ganz besonders Format ausgedacht, das aber trotzdem direkt per SQL*Loader in die Datenbank importiert werden kann.
1:PERSNR LFDNR EINTRT 2:UNTERNEHMEN 3:AUSGRD AUSTRT 1:[23456] [23456789] 2:[0] 3:[][23456789] 1:7000002001.04.1998 00:00:00 2:001 3: 15.07.1990 00:00:00 1:7000003001.08.1999 00:00:00 2:001

Datenmigration

245

In dem abgedruckten Muster dienen die ersten sechs Zeilen wieder zur Dokumentation bzw. zum Anzeichnen der in den Stzen enthaltenen Felder. Die eigentlichen Daten beginnen mit der Zeile sieben. Wie Sie dem Muster entnehmen knnen, bilden immer zwei bis drei Datenstze zusammen einen logischen Datensatz. Dabei werden die einzelnen Datenstze in der Datei mit Hilfe einer Satzart, die Sie auf den ersten beiden Stellen finden, unterschieden. Auerdem besteht die Mglichkeit, dass der letzte Datensatz einer Gruppe fehlt, weil die dort enthaltenden Daten (Austrittsgrund und Austrittsdatum) nicht vorhanden sind. Innerhalb der einzelnen Datenstze gilt wieder das Format der festen Feld bzw. Satzlnge, d.h. die Satzstze vom Typ 1: sind beispielsweise alle gleich formatiert. Auch diese Datei finden Sie wieder auf der Begleit-CD zum Buch unter dem Namen \DATEN\BVS.TXT. Ebenfalls dort finden Sie auch die fr den SQL*Loader bentigte Steuerdatei BVS.CTL.
-- Laden der BV's options ( skip = 2 ) load infile 'c:\temp\bvs.txt' badfile 'c:\temp\bvs.bad' discardfile 'c:\temp\bvs.dsc' discardmax 999 truncate continueif next (1:2) <> '1:' into table ubeispiel.bvs ( persnr lfdnr eintrt unternehmen ausgrd austrt )
Listing 2.88: Steuerdatei zum Einspielen der Beschftigungsverhltnisse

position(1:7) position(8:8) position(9:27) position(28:30) position(31:32) position(33:51)

char, integer external, date "DD.MM.YYYY HH24:MI:SS", char, char, date "DD.MM.YYYY HH24:MI:SS"

Betrachten Sie zunchst einmal den Parameter fr den Wert skip und werfen Sie dabei auch noch mal ein Auge auf den Musterausdruck der Datendatei. An dem Beispiel erkennen Sie, dass die bisherige Erluterung dieses Parameters nicht ganz richtig ist. Entweder Sie merken sich, dass mit Hilfe des skip-Parameters logische Datenstze berlesen werden oder sie interpretieren den Wert einfach als eine Anzahl von Schreibaussetzern, bevor das Programm mit dem Einfgen der neuen Datenstze beginnt.

246

Datenbankobjekte in einer Oracle-DB

Wirklich neu in unserer Steuerdatei ist die Anweisung continueif, mit deren Hilfe wir das Ladeprogramm anweisen, solange Stze aus der Datei einzulesen und aneinanderzuhngen, bis an den ersten beiden Stellen die Satzart 1: auftaucht.
continueif next (1:2) <> '1:'

Entsprechend sind auch die Positionierungen auf den gedachten, logischen Datensatz ausgerichtet. Dabei mssen Sie allerdings beachten, dass die Satzarten, also in unserem Beispiel jeweils die ersten beiden Stellen, nicht in dem logischen Datensatz enthalten sind. Das nachfolgende Beispiel verdeutlicht dieses Zusammenhang noch einmal, indem dort die ersten drei Stze aus der Datei und der hieraus gewonnenen logischen Datensatz gezeigt werden.
1:7000002001.04.1998 00:00:00 2:001 3: 15.07.1990 00:00:00 1 2 3 4 5 6 123456789012345678901234567890123456789012345678901234567890 7000002001.04.1998 00:00:00001 15.07.1990 00:00:00

Auf die eigentliche Verwendung des Programms hat das Ganze natrlich keinen Einfluss, d.h. wir starten wieder das Programm SQLLDR80.EXE unter Verwendung der neuen Steuerdatei.
set oracle_sid=db01 sqlldr80 userid=ubeispiel/manager control=c:\temp\bvs.ctl direct=true log=c:\temp\bvs.log

Varianten Neben den hier beschriebenen Mglichkeiten, bietet Ihnen der SQL*Loader noch eine Reihe von Varianten, deren konkrete Verwendung Sie bei Bedarf bzw. Interesse in der Oracle-Dokumentation nachlesen knnen. Von daher ist die jetzt folgende Aufzhlung eher als Ideenfindung zu verstehen, eine Art Brainstorming also.

Anstatt nur einer Importdatei (infile) knnen Sie in der Steuerdatei auch mehrere zu importierende Dateien vorgeben, indem Sie einfach mehrere infile-Parameter verwenden. In dem Fall knnen Sie ebenfalls mehrer badfile- oder discardfile-Einstellungen vornehmen, um fr die einzelnen Importdateien jeweils eigene Fehlerdateien zu erstellen.
infile 'datei01' infile 'datei02' badfile 'bad01' badfile 'bad02' discardfile 'discf01' discardfile 'discf02'

Das Programm SQL*Loader ist in der Lage, eine eventuell notwendige Zeichenkonvertierung durchzufhren, beispielsweise weil Sie Daten importieren, die auf anderen Zeichensatztabellen basieren.

Datenmigration

247

: :

Anstelle der truncate-Anweisung, die vor dem Import zum Lschen aller eventuell vorhanden Daten fhrt, knnen Sie auch die Anweisungen insert oder append verwenden. Dabei setzt insert voraus, dass die Tabelle leer ist, d.h. das Ladeprogramm wird abgebrochen, falls dem nicht so ist. Dagegen fhrt die append-Anweisung immer zum Anfgen der neuen Stze an die in der Tabelle vorhandenen Daten. Abgebrochene Ladevorgnge knnen wiederaufgesetzt werden. Hierzu existiert das spezielle Kommando continue_load, dass Sie in dem Fall anstatt des infile-Befehls verwenden mssen. Auerdem knnen Sie in dem Fall hinter dem insert into-Befehl den Aufsetzpunkt mit Hilfe eines skip-Kommandos festlegen. Ebenfalls besteht die Mglichkeit, mit einer Importdatei mehrere verschiedene Tabellen zu bedienen. In dem Fall mssen Sie zum einen mehrere into table-Befehle vorgeben und dabei mit Hilfe einer when-Klausel eine Bedingung spezifizieren, welche Datenstze in welche Tabelle zu importieren sind.

2.4.5

Wie geht es weiter?

Unsere kleine Personaldatenbank ist zumindest von seiner Struktur her weitestgehend fertiggestellt und die fr die verschiedenen Tabellen vorhandenen Beispieldaten haben wir ebenfalls aufgeladen. Damit haben wir eine gute Ausgangsbasis geschaffen, um uns mit Hilfe des nchsten Kapitels verschiedene Abfragemglichkeiten anzuschauen. Die endgltige Fertigstellung unserer Beispieldatenbank erfolgt, allerdings nur in Anstzen, erst am Ende des Kapitels PL/SQL-Programmierungen. Dort finden Sie zunchst eine systematische Einfhrung in PL/SQL und im weiteren Verlauf des Kapitels werden wir die noch fehlenden Prfungen anhand eines exemplarischen Beispiels erstellen bzw. programmieren. Abrechnungsergebnisse Im nchsten Schritt werden wir unsere Datenbank allerdings noch um eine Tabelle mit speziellen Ergebnisdaten erweitern. Diese Tabelle enthlt monatliche Abrechnungsergebnisse, die mitarbeiterbezogen mit Hilfe einer Lohnart gespeichert werden. Dabei verzichten wir in unserem Beispiel auf eine zur Lohnart passenden Referenztabelle. Die Tabelle knnen Sie in Ihrer Datenbank mit Hilfe des folgenden Skripts anlegen, das Sie in der Datei \DATEN\LOHNART.SQL finden.
drop table lohnarten; create table lohnarten ( persnr varchar2(11) not null, lfdnr smallint not null, gab date not null, la varchar2(3) not null, satzart varchar(2) default 'DM' not null, betr01 number(9,2) not null, betr02 number(9,2) not null,

248

Datenbankobjekte in einer Oracle-DB

betr03 betr04 betr05 betr06 betr07 betr08 betr09 betr10 betr11 betr12

number(9,2) number(9,2) number(9,2) number(9,2) number(9,2) number(9,2) number(9,2) number(9,2) number(9,2) number(9,2)

not not not not not not not not not not

null, null, null, null, null, null, null, null, null, null,

constraint satzart_check check (satzart in ('DM','TA','ST','LB')), constraint lohnarten_pk primary key (persnr, lfdnr, gab, la, satzart) ); commit;
Listing 2.89: Speichern der Abrechnungsergebnisse

Eine besondere Aufmerksamkeit sollten Sie einmal dem Datenfeld satzart, das ebenfalls Teil des Primrschlssels ist, schenken. Mit Hilfe dieser Satzart wird gesteuert, was in den einzelnen zur Lohnart gehrenden Betragsfeldern genau gespeichert ist. Standardmig in der Access-Datenbank sind die zugehrigen Daten in der Tabelle ORCLADMIN_LOHNARTN gespeichert. Ich habe sie hnlich wie die Gehaltsdaten als variabel lange Datenstze mit Verwendung eines Feldtrennzeichens exportiert, wobei Sie das Ergebnis auf Ihrer CD in der Datei \DATEN\LOHNARTEN.TXT finden. Zum Import verwenden wir wieder das Programm SQL*Loader. Eine fr den Import geeignete Steuerdatei finden Sie im gleichen Verzeichnis unter dem Namen LOHNARTEN.CTL, so dass Sie die Tabelle nach dem Anlegen mit Daten fllen knnen.

Abfragen

In diesem Kapitel werden wir uns mit den verschiedenen Mglichkeiten beschftigen, Abfragen an unsere Datenbank zu senden, d.h. wir beschftigen uns zum ersten Mal etwas systematischer mit SQL (= Structured Query Language). Dabei werden wir uns im ersten Teil mit Auswahlabfragen beschftigen. Im Anschluss daran lernen Sie die verschiedenen nderungsabfragen kennen, was in der Erstellung von selbstprogrammierten Cursors zur Durchfhrung von Datennderungen mndet. Das Ganze finden dann seinen Abschluss in einigen Ausfhrungen und Hinweisen zum Tuning bzw. der Ablaufkontrolle von Abfragen. Im letzten Teil dieses dritten Kapitels werden wir einen Abstecher ins Data Dictionary von Oracle unternehmen und uns dabei anschauen, welche Informationen die verschiednen Systemtabellen und Sichten fr uns bereithalten. Dabei geht die von mir praktizierte Vorgehensweise auch in diesem Kapitel wieder davon aus, dass Sie zum einen schon gewisse Grundkenntnisse und Erfahrungen aus anderen Datenbanksystemen haben und zum anderen sich nicht scheuen, bestimmte weitergehende Informationen in der Oracle-Dokumentation nachzuschlagen. Diese finden Sie, indem Sie die hier beschriebenen Befehle in der Oracle8 SQL-Referenz nachschlagen. Daneben befindet sich auch in dem Buch Oracle8 Concepts ein Kapitel SQL and PL/SQL mit einer zusammenhngenden Beschreibung des gesamten Themenkomplexes. Die in diesem Kapitel gezeigten kleineren Abfragebeispiele habe ich Ihnen auf Ihrer Begleit-CD in dem Verzeichnis \ABFRAGEN zusammengestellt. Fr jedes grere Kapitel finden Sie hier eine eigene Datei (z.B. ABFRAGE31.SQL), in der ich die ganzen Beispiele aneinandergehngt habe.

3.1

Einfache Auswahlabfragen

Genau wie in allen anderen relationalen Datenbanksystemen erfolgt die Abfrage oder nderung der gespeicherten Daten mit Hilfe von SQL. Damit sollte die Verwendung dieser Abfragesprache in allen relationalen Datenbanksystemen eigentlich gleich funktionieren, gbe es da nicht die produktspezifischen Spracherweiterungen bzw. Verfahrensvarianten. Mit anderen Worten: ohne Transact-SQL, PL/SQL oder Jet-SQL wre die Welt mal wieder bersichtlicher, aber sicherlich nicht einfacher, denn die einzelnen Spracherweiterungen wurden wohl kaum aus einer Bierlaune heraus entworfen, sondern sie entstanden im Laufe der Zeit, um Ihnen das Spektrum der Mglichkeiten zu vergrern bzw. die Arbeit zu erleichtern; die Alternative, dass alle Hersteller das gleiche Sppchen kochen, drfte wohl auch hier auf ewig eine Traumvorstellung bleiben.

250

Abfragen

In diesem Abschnitt mchte ich bei der Behandlung der Auswahlabfragen mit einem einfachen Beispiel beginnen und damit die grundstzliche Struktur einer solchen Abfrage erlutern. Einfach heit in diesem Fall, dass im Rahmen dieser Abfrage lediglich eine Tabelle gelesen wird. Schwierig, sofern man davon berhaupt reden kann, wird es nmlich frhestens dann, wenn mehrere Tabellen ins Spiel kommen, die dann im Rahmen der Abfrage sinnvoll miteinander verknpft werden mssen, damit das gewnschte Ergebnis zustande kommt.

3.1.1

Struktur einer Auswahlabfrage

Im Prinzip besitzt eine Auswahlabfrage eine sehr einfache Struktur und besteht in ihrer Grundform aus gerade mal zwei bis vier Abschnitten.
select <Auswahlliste> from <Tabellenliste> [where <Auswahl- und Verknpfungsbedingungen>] [order by <Sortierbedingungen>]

Der erste Abschnitt ist zwingend und wird mit Hilfe des Schlsselwortes select eingeleitet. Diesem Schlsselwort folgt eine Liste der gewnschten Datenfelder und Ausdrcke, d.h. im Rahmen einer solchen Auswahlabfrage knnen nicht nur Tabellenspalten, sondern auch komplexe Berechnungen durchgefhrt werden.
SQLWKS> select persnr, 2> substr(name,1,20) || '<', 3> 3*5-12, 4> sysdate 5> 6> from personalien; PERSNR ----------7000002 7000003 7000004 7000005 SUBSTR(NAME,1,20) 3*5-12 --------------------- ---------Karlo,Armin< 3 Heiden,Magareta< 3 Hardt,Andreas< 3 Nibelungen,Ellen< 3 SYSDATE -------------------21-AUG-00 21-AUG-00 21-AUG-00 21-AUG-00

Listing 3.1: Beispiel fr eine einfache Auswahlabfrage

Wie Sie dem Beispiel entnehmen knnen, verwendet die Abfrage nur die beiden zwingenden Abschnittes select und from. Mit Hilfe der select-Klausel werden hierbei insgesamt vier Spalten gebildet, wobei nur die erste eine direkte Beziehung zu einer Tabellenspalte aufweist. Die zweite Spalte liest immerhin noch das Feld name, das allerdings im Rahmen eines Ausdrucks verwendet wird. Die anderen beiden mit Hilfe von Ausdrcken gebildeten Spalten haben berhaupt keinen Bezug zu irgendwelchen Werten aus der zugrundeliegenden Tabelle. Innerhalb eines solchen Ausdrucks knnen Sie im Prinzip das gesamte Repertoire

Einfache Auswahlabfragen

251

: : : : :

der in den mit Hilfe der from-Klausel spezifizierten Tabellen vorhandenen Spalten, aller vorhandenen Systemfunktionen, aller selbsterstellten Funktionen (Paket-, Member- und einfache Funktionen), der verfgbaren Pseudo-Spalten wie zum Beispiel sysdate oder rownum, der vorhandenen Operatoren (z.B. +, -, * usw.),

verwenden. Wichtig ist, dass der auf diese Weise zusammengebastelte Ausdruck vom System auswertbar ist und ein Ergebnis zurckliefert. Im Unterschied zu einigen anderen Datenbanksystemen knnen Sie in solchen Ausdrcken jedoch keine direkten Unterabfragen verwenden, d.h. das folgende Beispiel knnen Sie in Oracle so nicht erstellen.
select a, b, c = (select sum(d) from xx2) from xx1

In solchen Fllen knnen Sie allerdings eine Funktion erstellen und die Unterabfrage in dieser Funktion verstecken. Die prinzipielle Vorgehensweise zum Erstellen solcher Funktionen haben Sie schon kennen gelernt und spter im Kapitel PL/ SQL-Programmierung werden wir auch ein Beispiel erstellen, wo wir innerhalb einer Funktion eine Auswahlabfrage verwenden. Mit Hilfe der from-Klausel erfolgt lediglich die Aufzhlung der in der Abfrage verwendeten Tabellen. hnlich wie bei der select-Anweisungen werden die einzelnen Tabellen auch hierbei wieder mit Hilfe eines Kommas (,) getrennt. Verwenden von Aliasnamen Es schadet nicht, wenn Sie sich zumindest fr die verwendeten Tabellen von vornherein angewhnen, fr jede der aufgezhlten Tabellen einen Aliasnamen zu vergeben. Solche Aliasnamen vereinfachen vor allem bei Abfragen mit mehreren Tabellen eventuell mehrfach vorkommende Spaltennamen eindeutig zu identifizieren. Wie gesagt schadet es aber nicht, wenn Sie Technik derart verinnerlichen, dass Sie sie auch bei einfachen Abfragen anwenden.
select a.persnr, substr(a.name,1,20) || '<', 3*5-12, sysdate from personalien a;

Ein solcher Tabellen-Aliasname wird meistens aus ein bis zwei Zeichen gebildet und innerhalb der from-Klausel direkt hinter dem Namen der Tabelle aufgefhrt. Anschlieend kann er an allen anderen Stellen der Abfrage zur eindeutigen Bestimmung der Spaltenherkunft verwendet werden, indem Sie den Aliasnamen der Tabelle zusammen mit einem Punkt dem Namen der Spalte voranstellen.

252

Abfragen

Natrlich knnen Sie eine Spalte auch ohne Aliasnamen eindeutig identifizieren, in dem Sie ihr den Namen der Tabelle voranstellen. Fr meinen Geschmack ist das aber wesentlich umstndlicher und artet in den allermeisten Fllen auch in wesentlich mehr Tipparbeit aus.
select personalien.persnr, substr(personalien.name,1,20) || '<', 3*5-12, sysdate from personalien;

Auch fr die in der select-Klausel aufgezhlten Spalten knnen Sie Aliasnamen vergeben, die anschlieend als Spaltenberschrift verwendet werden. Das hat allerdings nicht nur kosmetische Grnde, wenn man einmal berliegt, wofr solche Auswahlabfragen blicherweise verwendet werden. Die meisten Abfragen dieser Welt werden sicherlich im Rahmen eines Programms verwendet, das die gelieferten Daten am Bildschirm anzeigt oder irgendwie anders weiterverarbeitet. Im Rahmen eines solchen Programms bestehen meistens zwei Alternativen, die Werte der einzelnen Spalten abzufragen. Zum einen knnen die Werte mit Hilfe einer laufenden Nummer, die der in der select-Klausel verwendeten Reihenfolge entspricht, oder mit Hilfe der Spaltenberschrift abgefragt werden. Betrachten Sie nun noch einmal das Ergebnis unseres ersten Beispiels (vgl. Listing 3.1). Die dort gezeigten Ergebnisse mit Hilfe der vorhandenen berschriften abzufragen, macht sicherlich wenig Spa. Aus diesem Grund knnen Sie jeder Spalte mit Hilfe des Schlsselwrtchens as eine neue berschrift zuweisen, mit der Sie den Wert anschlieend innerhalb eines Programms abfragen knnen.
SQLWKS> select a.persnr, 2> substr(a.name,1,20) || '<' as name, 3> 3*5-12 as wert, 4> sysdate as datum 5> 6> from personalien a; PERSNR ----------7000002 7000003 7000004 7000005 NAME WERT --------------------- ---------Karlo,Armin< 3 Heiden,Magareta< 3 Hardt,Andreas< 3 Nibelungen,Ellen< 3 DATUM -------------------21-AUG-00 21-AUG-00 21-AUG-00 21-AUG-00

Listing 3.2: Einfache Abfrage mit eigenen berschriften und Tabellen-Aliasnamen

Ein solcher Spalten-Aliasname kann nahezu beliebig vergeben werden. Allerdings mssen Sie ihn in doppelten Anfhrungszeichen setzen, wenn er irgendwelche Sonderzeichen enthlt, wobei auch schon ein Leerzeichen aus der Sicht von Oracle ein besonderes Zeichen darstellt.
select a.persnr as "deine nummer",

Einfache Auswahlabfragen

253

Eindeutige Ergebnisse erzwingen Normalerweise sollten Sie Ihre Abfrage so gestalten, dass sie genau die von Ihnen gewnschten bzw. bentigten Ergebnisse liefern. Es gibt aber Situationen, da werden bestimmte Ergebniszeilen aufgrund der vorliegenden Datenkonstellationen mehrmals ausgeworfen. In dem Fall gibt es einfaches Mittel diese doppelten Ergebnisreihen zu vermeiden, in dem Sie hinter der select-Klausel als Erstes das Schlsselwort distinct verwenden.
SQLWKS> select plz from personalien; PLZ -----------62006 87770 ... 47239 79006 23 rows selected.
Listing 3.3: Abfrage der Postleitzahlen ohne distinct

Bei der gewhnlichen Abfrage (vgl. Listing 3.3) des Feldes Postleitzahlen plz aus unserer Personalstammtabelle erhalten Sie alle 23 importierten Datenstze. Wenn Sie die gleiche Abfrage anschlieend mit Hilfe des distinct-Parameters (vgl. Listing 3.4) verwenden, dann erhalten Sie dahingegen nur 18 Datenstze, d.h. fnf Datenstze wurden wegen gleicher Postleitzahlen aus der Ergebnismenge herausgestrichen.
SQLWKS> select distinct plz from personalien; PLZ -----------10006 18055 ... 87770 90546 18 rows selected.
Listing 3.4: Abfrage der Postleitzahlen unter Verwendung der Einschrnkung distinct

Meiner Meinung nach sollten Sie die distinct-Klausel nur in Ausnahmefllen und wohlbedacht einsetzen. Zum einen fhrt sie, wie Sie spter noch sehen werden, zu einem zustzlichen Arbeitsschritt bei der Ausfhrung Ihrer SQL-Abfrage. Zum anderen kann sie dazu fhren, dass bestimmte Fehler in Ihren Abfragen gar nicht zu Tage treten, da sie aufgrund der distinct-Anweisung verschleiert werden. Die folgende Anweisung soll diesen Sachverhalt verdeutlichen. Bei einer Abfrage hat sich vielleicht aufgrund eines Tipp- oder Kopierfehlers noch eine weitere Tabelle in der from-Klausel eingeschlichen.

254

Abfragen

select distinct a.persnr, a.name from personalien a, gehalt;

Trotzdem liefert die Abfrage wieder die vorhandenen 23 Personalstammstze, wohingegen Sie ohne die distinct-Klausel in unserem Fall 1104 Datenstze (Anzahl Personalien * Anzahl Gehaltsdatenstze) erhalten wrden. Nun knnte man meinen, dass ein solcher Fehler in echten Produktionsumgebungen mit entsprechend vielen Datenstzen sofort auffallen wrden. Dem ist aber nicht unbedingt so, denn zum einen basieren Produktionsumgebungen unter Umstnden auf extrem leistungsfhiger Hardware, so dass ein solcher Abfragepatzer nicht unbedingt zwingend zur Antwortszeiteskalation fhrt und zum anderen wird die Abfrage vielleicht innerhalb eines Batchprogramms verwendet und da fllt es vielleicht sowieso nicht auf, wenn das Programm statt mglicher fnf insgesamt 20 Minuten luft.

3.1.2

Where-Bedingungen

Nun beschftigen wir uns mit der ersten optionalen Klausel in einer Abfrage, mit deren Hilfe Sie die als Ergebnis bereitgestellten Datenstze durch Hinzufgen geeigneter Auswahlbedingungen einschrnken knnen. Wie Sie spter noch sehen werden, wird die where-Klausel jedoch nicht zur Programmierung echter Auswahlbedingungen verwendet, sondern mit ihrer Hilfe werden auch die Verknpfungen durchgefhrt, wenn mehrer Tabellen an der Abfrage beteiligt sind. Im Prinzip definieren Sie mit Hilfe der where-Bedingung einen beliebig komplexen Ausdruck, der insgesamt erfllt sein muss, damit der zugehrige Datensatz im Rahmen der Abfrage ausgewhlt wird. Im Prinzip entspricht der Aufbau einer einzelnen Abfragebedingung folgendem Schema:
where <Ausdruck-1> <Vergleichsoperator> <Ausdruck-2>

Bei den einzelnen Ausdrcken kann es sich um einfache Spalten, Konstanten oder wiederum um komplexe Gebilde handeln, die mit Hilfe von jeglicher Art von Funktionen, verschiedenen Spalten und Operatoren gebildet werden. Insgesamt ist dabei eigentlich nur wichtig, dass die beiden Ausdrcke zueinander passen, also vom gleichen oder zumindest hnlichen Datentyp sind, und damit berhaupt vergleichbar werden. Zwischen den beiden Ausdrcken befindet sich der sogenannte Vergleichsoperator, der wie sein Name schon sagt, die Vergleichsbedingung der beiden Ausdrcke festlegt. Vergleichsoperatoren Ich habe die wichtigsten Vergleichsoperatoren einmal mit Hilfe nun folgenden bersicht zusammengestellt, und die dort zu findenden Informationen fr Sie wahrscheinlich nicht besonders neu bzw. aufregend sein drften, habe ich mich bei deren Beschreibung auch bewusst kurz gefasst.

= Prft die beiden Ausdrcke auf exakte Gleichheit

Einfache Auswahlabfragen

255

> (<) Der linke Ausdruck muss grer (kleiner) als der Rechte sein. Wie so etwas bei Zahlen- oder Datumswerten zu verstehen ist, drfte eigentlich jedem klar sein, aber wann ist ein Text grer (kleiner) als ein anderer? Zwei Text bzw. Zeichenketten werden eigentlich in jeder Programmiersprache von links nach rechts verglichen. Dabei findet die Entscheidung statt, sobald die Zeichen an der aktuellen Vergleichsstelle n nicht mehr bereinstimmen, bzw. das Ende einer der beiden Zeichenketten vorzeitig erreicht wird. Wird ein solches vorzeitiges Ende erreicht, d.h. die eine Zeichenfolge stellt eine Verlngerung des anderen Textes dar, dann ist diejenige grer (kleiner), die lnger (krzer) ist, d.h. nur in dem Fall hat Gre auch etwas mit Lnge zu tun.
where 'Haha' > 'Hah'

Weichen die an Stelle n gefundenen Zeichen voneinander ab, dann regelt genau dieses Zeichen die Beziehung zwischen den beiden Zeichenfolgen.
where 'Ho' > 'Hahahahahaha'

In meinem einfachen Beispiel weicht der zweite Buchstabe der beiden Zeichenketten voneinander ab. Da aufgrund der Definition des Zeichensatzes das Zeichen o hinter dem Zeichen a liegt (im ASCII-Zeichensatz steht o auf Stelle 111 und a auf Stelle 97), ist die linke Zeichenfolge in der Tat grer als die rechte, obwohl diese wesentlich lnger ist. Im ASCII-Zeichensatz gilt fr die gewhnlichen druckbaren Zeichen die folgende Grenrelation: 0, 1, ..., A, B, ..., a, b. Das Ganze sieht im EBCDIC-Zeichensatz etwas anders aus, denn dort gilt die folgende Vergleichsregel: A, B, ..., a, b, ..., 0, 1. Welches Zeichen an welcher Stelle im Zeichensatz steht, knnen Sie im Zweifelsfall auch mit Hilfe der Standardfunktion ascii ermitteln, indem Sie der Funktion beispielsweise das zu untersuchende Zeichen als Argument bergeben.
SQLWKS> select ascii('0'),ascii('a'), ascii('A') from dual; ASCII('0') ASCII('A') ASCII('A') ---------- ---------- ---------48 97 65 1 row selected.

Fr diejenigen, die sich beim letzten Beispiel ber die komische Tabelle dual wundern noch ein Hinweis: Im Unterschied zu manch anderen Datenbanken erlaubt Oracle keine Verwendung von select, ohne gleichzeitig auch irgendeine Tabelle zu spezifizieren. Aus diesem Grund existiert diese dual-Tabelle, die keine eigentlichen Werte, sondern nur einen einzigen Dummy-Datensatz enthlt. >= (<=) Der linke Ausdruck muss grer (kleiner) oder exakt gleich dem rechten Ausdruck sein.

256

Abfragen

: :

<> (!=) Der linke und rechte Ausdruck mssen verschieden sein. Die beiden Operatoren sind gleichbedeutend, d.h. welchen Sie verwenden ist reine Geschmacksache. (not) like Der linke Ausdruck soll (nicht) so hnlich wie der rechte sein. Was hnlich dabei genau bedeuten soll, dass knnen Sie mit Hilfe von Platzhaltern im rechten Ausdruck festlegen. Ohne die Verwendung von Platzhaltern funktioniert der Operator like genau wie ein gewhnliches Gleichheitszeichen. Als Platzhalter knnen Sie einen Unterstrich _ oder ein Prozentzeichen % verwenden. Dabei stellt der Unterstrich ein Platzhalter fr genau ein Zeichen dar, wohingegen das Prozentzeichen einen beliebig langen Platzhalter vorgibt. (not) in Der linke Ausdruck soll (nicht) in einer Liste enthalten sein, die Sie mit Hilfe des rechten Ausdrucks spezifizieren. Dabei ist die Abfragebedingung erfllt, wenn der linke Teil keinem (not) bzw. einem einzigen Element aus der Liste entspricht. is (not) null Wie Sie aus der Anlage von Tabellen wissen, besteht durchaus die Mglichkeit, in einer Spalte nichts (null), d.h. keinen konkreten Wert zu speichern. Das Problem dabei ist allerdings, dass nichts eben mit nichts vergleichbar ist, d.h. der Komfort, bei der Anlage der Datenstze nichts eingeben zu mssen, mutiert beim Abfragen unter Umstnden zu einem kleinen Problem. Gerade bei Datumswerten, wo diese null-Werte oftmals zulssig sind, kann sich daher hufiger der Fehlerteufel in Ihre Abfragen einschleichen. Die nachfolgende Abfrage liefert alle Mitarbeiter, deren Datum im Feld Datum Familienstand kleiner als das aktuelle Tagesdatum ist.
select a.persnr, a.name from personalien a where a.familienstd_dt < sysdate

Nichts (null) ist aber nicht kleiner als irgendetwas anderes und deshalb werden die Mitarbeiter ohne einen Wert in diesem Feld auch nicht selektiert. Um nun auch diese Mitarbeiter mit auszuwhlen, htten Sie im vorliegenden Beispiel zwei Mglichkeiten. Entweder Sie ergnzen die Abfragebedingung um ein weiteres Auswahlkriterium, das Sie mit Hilfe eines or-Operators verknpfen
where a.familienstd_dt < sysdate or a.familienstd_dt is null

oder Sie substituieren zur Laufzeit den null-Wert durch irgendeinen anderen Standardwert. Letzteres knnen Sie mit Hilfe der Funktion nvl durchfhren. Diese Funktion erhlt als ersten Parameter die zu berprfende Spalte und als zweiten Parameter den zu verwendenden Ersatzwert, wenn die Spalte den Wert

Einfache Auswahlabfragen

257

null enthlt. Als Rckgabe liefert die nvl-Funktion dann entweder den Wert der bergebenen Spalte oder den vorgegebenen Ersatzwert.
where nvl(a.familienstd_dt, sysdate-1) < sysdate

In meinem Beispiel substituiere ich nicht gefllte Datenfelder durch das Datum des Vortags (sysdate 1 ). Selbstverstndlich knnen Sie stattdessen auch eine beliebige andere Datumskonstante oder auch eine andere Tabellenspalte verwenden. Aus meiner Sicht ist der Umgang mit nvl oftmals einfacher, als die Programmierung zustzlicher is null-Bedingungen, die Sie ja vor allem auch richtig bzw. sinnvoll in die brige where-Bedingung einbauen mssen. Der Operator is null entspricht also nicht ganz dem oben abgebildeten Schema, da hierbei der zweite Vergleichsausdruck fehlt. Natrlich knnen wir das Ganze auch mit etwas Gewalt in unser Schema hineinpressen, indem wir so tun, als sei in Wirklichkeit lediglich das Wrtchen is der Operator, der als zweiten Ausdruck zufllig die Konstante null erwartet. (not) between A-1 and A-2 Auch dieser Fall passt nicht so ganz in unser bisheriges Schema. Hierbei wird der links stehende Ausdruck mit den hinter between spezifizierten Ausdrcken A-1 und A-2 verglichen, wobei diese als Intervall interpretiert werden. Dabei werden die linke bzw. rechte Grenze jeweils durch die Ausdrcke A-1 bzw. A-2 gebildet. Ist der links stehende Ausdruck (nicht) in dem Intervall enthalten, dann gilt die zughrige Auswahlbedingung als erfllt.
where substr(a.name,1,3) between 'Bec' and 'Keu'

In dem Beispiel mssen die ersten drei Stellen des Namens im Intervall zwischen Bec und Keu liegen, wobei die beiden Grenzen selbst noch zur Auswahl hinzugehren. Die Anweisung stellt also eine vereinfachende Sonderform fr ein geschlossenes Intervall zur Verfgung, das Sie ansonsten auch folgendermaen programmieren knnten:
where substr(a.name,1,3) >= 'Bec' and substr(a.name,1,3) <= 'Keu'

Logische Verknpfungsoperatoren Wie Sie dem letzten Beispiel entnehmen konnten aber wahrscheinlich auch schon lngst wissen, gibt es neben den Vergleichsoperatoren auch noch weitere Verknpfungsoperatoren, mit denen Sie die einzelnen Auswahlbedingungen zu einer komplexen Gesamtbedingung verbinden knnen. Allerdings ist die hierbei angebotene Auswahl an Mglichkeiten im Vergleich zu einigen anderen Datenbanksystemen oder Programmiersprachen doch eher bescheiden, denn im aktuellen Werkzeugkasten finden Sie nur die drei Operatoren und, oder bzw. nicht. Die Bedeutung dieser drei Operatoren habe ich mit Hilfe der Tabelle 3.1 kurz zusammengefasst.

258

Abfragen

Operator and

Beschreibung Logische und-Verknpfung zweier Auswahlbedingungen. Das Ergebnis ist nur dann erfllt (wahr), wenn beide Einzelbedingungen gleichzeitig erfllt (wahr) sind. Logische oder-Verknpfung. Das Ergebnis dieser Verknpfung ist nur dann falsch, wenn beide Einzelbedingungen gleichzeitig nicht erfllt (falsch) sind. Nicht-Operator. Fhrt zur Umkehrung des Wahrheitswertes einer Auswahlbedingung.

or not

Tabelle 3.1: Beschreibung der logischen Verknpfungsoperatoren

Auer diesen drei Operatoren knnen Sie noch in einem beliebigen Mae Klammern setzen, um die Reihenfolge der Verknpfungen bzw. deren Auswertung zu beeinflussen. Beachten Sie, dass ohne die Verwendung irgendwelcher Klammern die and-Operatoren Vorrang vor den or-Operatoren haben. Noch vorrangiger wird der Operator not verarbeitet, der stets als Erstes ausgewertet wird. Ich hatte anfangs von Bescheidenheit gesprochen. Was ich damit meine ist, dass logische Operatoren zur Beschreibung einer quivalenz (eqv), Implikation (Folge; imp) oder dem exklusiven Oder (xor) fehlen. Allerdings habe ich diese drei Operatoren bisher nicht so hufig vermisst, da sie zum einen zumindest im kaufmnnischen Bereich nicht so ganz so oft bentigt werden und zum anderen mit Hilfe der vorhandenen Operatoren, wenn auch etwas umstndlicher, nachgebildet werden knnen.
Verknpfung quivalenz (<=>) Beschreibung Nehmen wir zwei Einzelbedingungen A und B, dann spricht man A ist quivalent zu B genau dann, wenn die Bedingungen A und B den gleichen Wahrheitswert liefern, d.h. entweder A und B sind beide erfllt oder beide Bedingungen sind gleichzeitig nicht erfllt. Genau in den beiden Fllen ist also auch die quivalenz-Verknpfung erfllt. Werden zwei Einzelbedingungen A und B mit Hilfe einer Implikation verknpft, dann sagt man hierzu A impliziert B oder aus A folgt B. Hierbei gilt die gesamte Verknpfung nur dann als nicht erfllt, wenn A gilt und gleichzeitig B nicht erfllt ist, d.h. wenn die Folge trotz erfllter Voraussetzung nicht eintritt. Wie viel geschundenes Beispiel fr diese Sachverhalt ist die Aussage Wenn es regnet (A), dann wird die Strae nass (B). Diese Aussage gilt in allen Fllen, in denen der Behauptung nicht direkt widersprochen wird als erfllt. Es ist trocken und die Strae ist nass; na und, vielleicht fhrt gerade ein Reinigungsfahrzeug vorbei (wahr). Es regnet und die Strae wird nass; prima, genau dass wurde behauptet (wahr). Es regnet nicht und die Strae ist trocken; schn, ist aber eigentlich vllig egal (wahr). Es regnet, aber die Strae bleibt trocken; oho, das steht im direkten Widerspruch zur Aussage (falsch).

Implikation (=>)

Einfache Auswahlabfragen

259

Verknpfung Exklusives Oder (>-<)

Beschreibung Eine per exklusivem Oder verknpfte Einzelbedingungen A und B gilt als erfllt, wenn die beiden einzelnen Bedingungen einen unterschiedlichen Wahrheitswert aufweisen, d.h. wenn A erfllt ist, dann muss B falsch sein und umgekehrt. Mit anderen Worten entspricht dieser Operatore der nicht erfllten quivalenz. Entsprechend der Tabelle 3.3 gilt also A>-<B = (A B (A B)) = (A B) (A B)

Tabelle 3.2: Weitere logische Verknpfungen

Ich habe die Nachbildung dieser drei logischen Verknpfungen einmal mit Hilfe der drei folgenden Tabellen nachgestellt bzw. demonstriert. Die in den Tabellen auftauchenden Sonderzeichen fr die quivalenz (<=>), Implikation (=>), Konjunktion (and-Verknpfung, ), Disjunktion (or-Verknpfung, ) oder die Negation (not-Verknpfung) kommen Ihnen aus der Schulmathematik sicherlich noch bekannt vor.
A w w f f B w f w f A <=> B w f f w AB w f f f AB w w w f (A B) f f f w A B (A B) w f f w

Tabelle 3.3: Auflsung einer quivalenz A w w f f B w f w f A => B w f w w A f f w w A B w f w w

Tabelle 3.4: Auflsung einer Implikation A w w f f B w f w f A >-< B f w w f (A B) w f f f (A B) f w w w A B w w w f (A B) (A B) f w w f

Tabelle 3.5: Auflsung einer exklusiven Oder-Verknpfung

3.1.3

Ergebnisse sortieren

Wie Sie schon der ganz am Anfang dargestellten Struktur entnehmen konnten, besteht natrlich auch die Mglichkeit, die im Rahmen einer Abfrage selektierten

260

Abfragen

Datensatze sortiert zu empfangen. Hierzu knnen Sie die order by-Klausel verwenden, die - sofern vorhanden den letzten Abschnitt einer Auswahlabfrage darstellt und mit deren Hilfe alle bentigten Sortierbegriffe durch Komma getrennt aufgezhlt werden. Bei der Verwendung dieser Sortierklausel haben Sie im Prinzip folgende zwei Mglichkeiten. Zum einen knnen Sie als Sortierbegriff nahezu jede Spalte aus den an der Abfrage beteiligten Tabellen (from-Klausel) oder einen beliebigen gltigen Ausdruck verwenden. Wichtig dabei ist eigentlich nur, dass die Spalte oder der erstellte Ausdruck ein sinnvolles Sortierkriterium darstellt.
select a.persnr, a.name from personalien a order by substr(a.name,1,5), a.persnr;

Zum anderen knnen Sie sich innerhalb der order by-Klausel auch direkt auf die in der select-Klausel aufgezhlten Spalten beziehen, indem Sie statt eines Namens oder eines Ausdrucks die entsprechende Nummer der Spalte verwenden. Im nchsten Beispiel finden Sie hierfr ein Beispiel. Statt der Verwendung der Spalte a.persnr, wird innerhalb der Sortieranweisung einfach als zweites Sortierkriterium einfach Bezug auf die erste Spalte der select-Anweisung genommen.
select a.persnr, a.name from personalien a order by substr(a.name,1,5), 1;

Als dritte Variante knnen Sie auch die bei der Spaltendefinition vergebenen Aliasnamen als Sortierkriterien verwenden, wobei die sogar wiederum in einen Ausdruck eingebaut werden knnen. Beachten Sie auch hierbei wieder die besondere Verwendung des fr die erste Spalte vergebenen Alternativnamens, da dieser ein Sonderzeichen (Leerzeichen) enthlt.
select a.persnr as "unsere nummern", a.name dername from personalien a order by substr(dername,1,5) desc, "unsere nummern" asc;

Auf- bzw. absteigend Sortieren Standardmig sortiert Oracle die Daten immer aufsteigend entsprechend den vorgegebenen Sortierkriterien. Um die Daten absteigend zu sortieren mssen Sie dem Sortierkriterium das Schlsselwort desc (descending = absteigend) anfgen. Wie schon gesagt, entspricht die aufsteigende Sortierung dem Standard, und trotzdem knnen Sie dies dokumentieren, indem Sie das Schlsselwort asc (ascending = aufsteigend) verwenden. Im nchsten Beispiel wird die Abfrage entsprechend der ersten fnf Namenszeichen absteigend und nach Personalnummern aufsteigend sortiert.
select a.persnr, a.name from personalien a order by substr(a.name,1,5) desc, 1 asc;

Einfache Auswahlabfragen

261

3.1.4

Gruppierungen

Oftmals besteht die Notwendigkeit, die aus einer Abfrage resultierenden Daten nicht einzeln anzuzeigen, sondern die Ergebnisse nach bestimmten Kriterien zusammenzufassen. Ein besonders geeignetes Demonstrationsobjekt hierfr finden Sie unserer Ergebnistabelle lohnarten, in der fr jeden Mitarbeiter pro Jahr, Lohnart und Monat die whrend einer Gehaltsabrechnung entstandenen Abrechnungsergebnisse gespeichert werden. Bei den gruppierten Abfragen erweitert sich unser bisheriges select-Schema um genau zwei weitere Klauseln.
select <Auswahlliste> from <Tabellenliste> [where <Auswahl- und Verknpfungsbedingungen>] group by <Gruppierfelder> having <Auswahlbedingung fr die Gruppenbegriffe> [order by <Sortierbedingungen>]

Die eine der beiden neuen Klauseln heit group by und dient zur Vorgabe der gewnschten Gruppierbegriffe, die andere Klausel hat den Namen having und ermglicht die Erstellung zustzlicher Auswahlbedingungen, die allerdings erst auf der Gruppierungsebene angewendet werden. Die group by-Klausel Betrachten Sie einmal die Tabelle lohnarten, in der die Abrechnungsergebnisse eines Mitarbeiters pro Jahr und Lohnart gespeichert werden. blicherweise enthlt diese Tabelle pro Jahr eine Reihe von verschiedenen Lohnarten, mit denen die einzelnen Gehaltsbestandteile aufgeschlsselt werden.
SQLWKS> select * from lohnarten 2> PERSNR LFDNR GAB LA SA BETR01 BETR02 BETR03 BETR04 BETR05 ------- -------- ----------- --- -- ------ ------ ------ ------ -----7000005 0 01-JAN-98 350 DM 0 0 0 0 2148 7000005 0 01-JAN-99 350 DM 0 0 0 0 1013.38 7000005 0 01-JAN-98 370 DM 0 0 0 0 0

Sicherlich werden die Daten manchmal in dieser detaillierten Form gebraucht, jedoch bentigt man bestimmte Informationen oftmals nur in verdichteter Form. Beispielsweise interessiert gerade mal wieder die Lohnsumme pro Lohnart fr das Jahr 1999 und bevor Sie nun ein Programm mit einer entsprechenden Gruppenwechsellogik schreiben, knnen Sie die bentigten Informationen auch mit Hilfe einer gruppierenden Abfrage ermitteln.
select a.la, sum(a.betr01) as dm01 from lohnarten a where to_char(gab,'YYYY')='1999' and satzart = 'DM' group by a.la;

262

Abfragen

Hierbei mssen Sie zunchst einmal die zu gruppierenden Felder mit Hilfe der group by-Klausel festlegen, so dass die Abfrage anschlieend bei jedem Wechsel der hier aufgezhlten Felder oder Ausdrcke einen internen Gruppenwechsel durchfhrt. In unserem Beispiel war das lediglich bei der Lohnart gewnscht, weshalb diesmal eine sehr einfache Gruppierungsklausel entsteht. Alle diese gruppierten Felder drfen Sie ganz gewhnlich in der select-Klausel verwenden, wohingegen Sie alle anderen Spalten nur noch zusammen mit einer sogenannten Aggregatfunktion benutzen knnen. Eine solche Aggregatfunktion (vgl. Tabelle 3.6) legt fest, was mit dem innerhalb der Funktion verwendeten Feld oder Ausdruck beim Gruppenwechsel passieren soll.
Aggregatfunktion avg Beschreibung berechnet fr die bergebene Spalte bzw. den verwendeten Ausdruck den Durchschnitt fr alle Werte der zugehrigen Gruppe. Diese Funktion kann nur zusammen mit numerischen Spalten bzw. Ausdrcken verwendet werden. zhlt die zur Gruppe zugehrigen Datenstze. Als Funktionsargument knnen sie irgendetwas verwenden, weshalb die Funktion meistens in der Form count(*), count(1) oder count('x') verwendet wird. Sofern Sie als Argument eine regulre Spalte verwenden, dann zhlt die Funktion die Anzahl der Werte, die ungleich null sind. liefert den grten Wert der verwendeten Spalte bzw. des bergebenen Ausdrucks. Wie Sie bei der Beschreibung der Vergleichsoperatoren innerhalb der where-Bedingung schon gesehen haben, ist der Begriff der Gre auf nahezu jeden gngigen Datentyp anwendbar, weshalb die max-Funktion auch ziemlich universell einsetzbar ist. Eine Abfrage der Form select max(ort) liefert natrlich nicht im umgangssprachlichen Sinne die grte Stadt, sondern lediglich den Ort, fr dessen Namen es im Rahmen eines gewhnlichen grer-Vergleichs fr Zeichenfolgen keinen passenden Datensatz mehr innerhalb der Gruppe gibt. Den letzten Teil des Satzes kann man natrlich auch etwas verstndlicher beschreiben. Stellen Sie sich die Orte bzw. das entsprechend verwendete Feld innerhalb der Gruppe aufsteigend sortiert vor, dann liefert min den obersten und max den untersten Eintrag aus dieser Liste zurck. min Im Unterschied zu max liefert die Funktion min den kleinsten Wert der verwendeten Spalte bzw. des bergebenen Ausdrucks. Ansonsten gilt alles das fr max Gesagte auch fr die min-Funktion. berechnet fr das bergebene Feld bzw. den verwendeten Ausdruck die Summe fr alle zur Gruppe gehrenden Datenstze. Naheliegenderweise funktioniert diese Funktion wieder nur zusammen mit numerischen Feldern bzw. Ausdrcken. Werte mit dem besonderen Inhalt null werden bei der Summenbildung nicht bercksichtigt. Diese beiden Funktionen, mit deren Hilfe Sie fr die bergebenen Spalten die Standardabweichung oder Varianz berechnen knnen, erwhne ich hier eigentlich nur, weil die Liste der Aggregatfunktionen damit vollstndig aufgezhlt ist.

count

max

sum

stddev, varance

Tabelle 3.6: bersicht der wichtigsten Aggregatfunktionen

Einfache Auswahlabfragen

263

Wenn man sich die Beschreibung der Aggregatfunktionen durchliest, dann erhlt man den Eindruck, dass diese bei ihrer Verarbeitung ziemlich intelligent mit nullWerten umgehen, indem solche Werte einfach berlesen werden. Das ist prinzipiell auch richtig, aber dennoch besteht die Mglichkeit, dass eine Aggregatfunktion, von der count-Funktion einmal abgesehen, selbst den Wert null als Ergebnis zurckliefert. Das passiert beispielsweise immer dann, wenn entweder gar keine Datenstze vorhanden sind oder alle Spalten der aktuellen Gruppe den Wert null besitzen. Im brigen funktionieren die Aggregatfunktionen auch ohne die Verwendung der group by-Klausel, wobei die Funktionen in dem Fall die gesamte Ergebnismenge der Abfrage verarbeiten. Dies wollen wir einfach mal mit Hilfe der Personalientabelle ausprobieren und dabei das variable Verhalten der count-Funktion und die minund max-Funktionen zusammen mit Zeichenfolgen beobachten.
SQLWKS> select count(*), count(familienstd_dt), min(ort), max(ort) 2> from personalien; COUNT(*) COUNT(FAMI MIN(ORT) MAX(ORT) ---------- ---------- ------------------------------ ----------23 10 Baden-Baden Wiesbaden 1 row selected.
Listing 3.5: Verwendung der Aggregatfunktionen ohne group by

Beachten Sie die Abweichung der ersten beiden Spalten. In der ersten finden Sie in der Tat die Anzahl der selektierten Datenstze, wohingegen die zweite Spalte die Anzahl der Flle zhlt, in denen das Feld Datum Familienstand einen regulren Wert enthlt. Die having-Klausel Die having-Klausel wird gewhnlich zusammen mit gruppierenden Abfragen verwendet und stellt eine Art zustzlicher where-Bedingung auf Gruppenebene dar. Mit Hilfe dieser Klausel knnen Sie also auf Gruppenebene zustzliche Auswahlbedingungen definieren, die anschlieend regeln, ob die zugehrige Gruppe berhaupt in der Ergebnismenge enthalten ist. Kehren wir hierzu zunchst zu unserem Eingangsbeispiel des vorherigen Buchabschnitts zurck. Dort hatten wir die Januar-Lohnsummen fr das Jahr 1999 pro Lohnart ausgewertet.
SQLWKS> 2> 3> 4> 5> select la, sum(betr01) from lohnarten where gab = to_date('01.01.1999','DD.MM.YYYY') and satzart = 'DM' group by la;

LA SUM(BETR01 --- ---------300 1054.73 301 0

264

Abfragen

302 0 305 0 315 26.14 316 0 350 0 352 0 354 0 360 0 372 0 383 0 480 153.39 660 0 680 0 15 rows selected.

Wie Sie der Auswertung entnehmen knnen, gibt es dabei eine Menge von Lohnarten, bei denen die Januarsumme den Wert 0 ergibt, wobei wir genau diese Ergebniszeilen im nchsten Schritt herausfiltern wollen. Mit Hilfe einer gewhnlichen where-Bedingung ist das allerdings nicht mglich, denn die greifen jeweils auf der Ebene der einzelnen Datenstze und unsere Filterbedingung kann erst auf Gruppenebene durchgefhrt werden.
select la, sum(betr01) from lohnarten where gab = to_date('01.01.1999','DD.MM.YYYY') and satzart = 'DM' group by la having sum(betr01) <> 0;

Mit Hilfe der having-Klausel ist genau das mglich. In unserem Beispiel geben wir vor, dass die Gruppensumme des Feldes betr01 ungleich 0 sein muss, damit die zugehrige Datensatzgruppe in die Ergebnismenge der Abfrage bernommen wird. Im Groen und Ganzen unterscheidet sich die having-Klausel eigentlich nicht von gewhnlichen where-Bedingungen, d.h. Sie knnen beispielsweise die gleichen Vergleichs- und Verknpfungsoperatoren verwenden um komplexe Gruppenfilter zu erstellen. Das Einzige was Sie eigentlich beachten mssen ist, dass Sie hierbei alle Spalten, die nicht als Gruppierbegriff verwendet werden und dementsprechend nicht innerhalb der group by-Klausel aufgezhlt wurden, nur zusammen mit den schon beschriebenen Aggregatfunktionen verwenden knnen. Zur Verdeutlichung der ganzen Zusammenhnge finden Sie im Folgenden noch einmal ein zugegebenerweise etwas an den Haaren herbeigezogenes Beispiel. Wir suchen pro Ort den kleinsten Namen, wobei uns nur Orte interessieren, in denen genau ein Mitarbeiter verheiratet ist, d.h. es soll pro Ortsgruppe genau einen Datensatz geben, bei dem das Feld Datum Familienstand ausgefllt ist. Zustzlich soll die Gruppe nur dann selektiert werden, wenn der kleinste und grte Name der Gruppe bestimmten Kriterien gengt.

Einfache Auswahlabfragen

265

SQLWKS> 2> 3> 4> 5> 6>

select ort, min(name) from personalien group by ort having count(familienstd_dt) = 1 and ( min(name) like 'B%' or max(name) < 'S'); MIN(NAME) -------------------Keun,Monika Heler,Sascha Hilsamer,Kurt Beckmann,Yonne Bruckner,Yonne Karlo,Ellen

ORT -----------------------------Duisburg Engelstadt Eschborn Frankfurt Gimbsheim Rostock 6 rows selected.

3.1.5

Spalten vertexten

Manchmal mchte man gar nicht die direkt in der Tabelle gespeicherten Werte lesen, sondern diese bersetzen. Normalerweise wird dies mit Hilfe einer entsprechenden Referenztabelle durchgefhrt, in der die zu einem Schlssel gehrende berseztung gespeichert wird. In unserer Beispielsdatenbank finden Sie hierfr einige Muster, beispielsweise werden die Lnder mit Hilfe der entsprechenden Lndertabelle vertextet. Alternativ lassen sich Spalten aber auch whrend der Abfrage mit Hilfe der decodeFunktion umwandeln bzw. vertexten, was immer dann sinvoll sein kann, wenn die umzusetzenden Schlssel keine besonders groe Streuweite aufweisen. Ein Beispiel hierfr findet sich in der Spalte geschlecht bei den Personalstammdaten.
select decode(geschlecht, 'M','mnnlich', '1','mnnlich', 'W','weiblich', '2','weiblich') from personalien;

Wie Sie dem Beispiel entnehmen knnen, wird das Geschlecht mit Hilfe der decodeFunktion in entsprechende konstante Texte umgesetzt, was aufgrund des eingeschrnkten und vor allem konstanten Wertebereichs ertrglich ist. Das von der decode-Funktion fr einen Schlssel gelieferte Ergebnis muss allerdings nicht unbedingt einen solch einfachen Aufbau haben, sondern kann selbst wieder das Ergebnis eines Ausdrucks unter Verwendung weiterer Spalten sein.
select decode(geschlecht, 'M','Herr '1','Herr 'W','Frau '2','Frau from personalien; ' ' ' ' || || || || name, name, name, name)

266

Abfragen

3.2

Verknpfungen

Im nchsten Schritt wollen wir uns nun von den seichten zu etwas tieferen Gewssern begeben, was bertragen auf unsere Abfragen bedeutet, dass wir jetzt mehr als eine Tabelle zusammen in einer Selektion verwenden wollen. In dem Fall ndert sich die Struktur der eben beschriebenen Abfragen eigentlich kaum. Im Wesentlichen wird zunchst einmal die from-Klausel erweitert, indem Sie dort alle bentigten Tabellen aufzhlen. Auerdem bentigen Sie in der Regel zustzlich spezielle where-Bedingungen, mit denen die einzelnen Tabellen miteinander verknpft werden. Im folgenden Beispiel werden die Tabellen Personalien und Gehlter gemeinsam ausgewertet und hierzu ber das gemeinsame Feld der Personalnummer miteinander verknpft.
SQLWKS> select a.persnr, a.name, b.gab, b.gehalt 2> from personalien a, 3> gehalt b 4> where b.persnr = a.persnr; PERSNR ----------7000001 7000002 7000002 7000003 7000004 7000004 7000004 7000005 NAME --------------------------Frisch,Berta Karlo,Armin Karlo,Armin Heiden,Magareta Hardt,Andreas Hardt,Andreas Hardt,Andreas Nibelungen,Ellen GAB GEHALT -------------------- ---------01-JAN-90 4500 01-APR-98 4750 01-APR-99 4980 01-AUG-99 6500 01-APR-98 7250 01-JUL-98 7250 01-APR-99 7850 01-APR-98 6200

Listing 3.6: Einfache Verknpfung zweier Tabellen

Betrachtet man diese Abfrage bzw. ihr Ergebnis, dann entsteht auf den ersten Blick vielleicht der Eindruck, die where-Bedingung htte pltzlich sowohl erweiternden als auch restriktiven Charakter. Bestimmte Mitarbeiter tauchen auf einmal mehrfach auf, wohingegen andere in der Abfrage gar nicht mehr erscheinen. Vom Ergebnis her betrachtet, knnte man glauben, aufgrund der Verknpfung des gemeinsamen Feldes wrden die beiden abgefragten Tabellen synchronisiert (vgl. Abb 3.1). Dabei werden Datenstze herausgestrichen, die nicht in beiden Tabellen vorkommen, wohingegen manchmal auch Datenstze vervielfltigt werden, wenn das gemeinsame Feld in der anderen Tabelle mehrfach vorkommt.

Verknpfungen

267

select a.persnr, a.name, b.persnr, b.gab, b.gehalt from personalien a, gehalt b where b.persnr = a.persnr personalien a
7000001 7000002 7000002 7000003 7000005 7000005 7000005 Frisch,Berta Karlo,Armin Karlo,Armin Heiden,Magareta Niebelungen, Ellen Niebelungen, Ellen Niebelungen, Ellen

gehalt b
7000001 7000002 7000002 7000003 7000004 7000005 7000005 7000005 01.01.1990, 4500 01.04.1998, 4750 01.04.1999, 4980 01.08.1999, 6500 01.08.1999, 2300 01.04.1998, 6200 01.04.1998, 6200 01.04.1998, 6200

Abbildung 3.1: Synchronisieren der beiden abgefragten Tabellen

Wenn berhaupt, dann ist diese Betrachtung bzw. Erklrung allerdings nur aus Sicht des Abfrageergebnisses her richtig, denn die Verfahrensweise zur Erreichung dieses Ziels ist eine ganz andere. Zunchst einmal werden die beiden Tabellen gemischt, wobei jeder Datensatz der einen mit jedem Datensatz der anderen Tabelle kombiniert wird. Hierdurch entsteht eine logische Tabelle, die zum einen alle in der select-Klausel verwendeten Felder enthlt (vgl. Tabelle 3.7) und deren Datensatzanzahl zum anderen dem Produkt der Datenstze aus den verknpften Tabellen entspricht.
a.persnr 7000002 7000002 7000002 7000002 ... 7000003 7000003 7000003 ... Heiden, Margareta Heiden, Margareta Heiden, Margareta a.name Frisch, Berta Frisch, Berta Frisch, Berta Frisch, Berta b.persnr 7000002 7000002 7000004 7000005 ... 7000002 7000002 7000003 ... 01.04.1998 01.04.1999 01.08.1999 4750 4980 6500 b.gab 01.04.1998 01.04.1999 01.08.1999 01.04.1998 b.gehalt 4750 4980 2300 6200

Tabelle 3.7: Erstellen eines kartesischen Produkts der verknpften Tabellen

In diesem sogenannten kartesischen Produkt wird dann die spezifizierte whereBedingung ausgefhrt, wobei es sich jetzt ja eigentlich wieder um eine gewhnliche Auswahlbedingung handelt, mit der zwei Spalten der logischen Tabelle miteinander verglichen werden. In unserem Beispiel sollen die Spalten a.persnr und b.persnr gleich sein, was dabei herauskommt, dass knnen Sie der Tabelle 3.7 ent-

268

Abfragen

nehmen, wobei die fettgedruckten Zeilen die ausgewhlten Datenstze darstellen sollen. Also handelt es sich bei der where-Bedingung einer solchen verknpfenden Abfrage doch nicht um ein wundersames Instrument, dass zu einer Vermehrung von Datenstzen fhren kann, sondern vielmehr ist es die einzige Waffe, mit der Sie das extreme Populationsverhalten der in der from-Klausel aufgezhlten Tabellen einschrnken knnen. Betrachten wir nun noch einmal die Erstellung des im Zusammenhang mit der Tabelle 3.7 beschriebenen kartesischen Produkts. Dieses wird in Wirklichkeit natrlich mglichst niemals gebildet, denn ansonsten wrden solche Abfragen in groen Datenbanken niemals zu einem Ende kommen. Stellen Sie sich einmal die folgende Aufgabe vor: Sie sollen aus zwei Bchern die Seiten mit einem bestimmten Begriff zusammenlegen. Wrden Sie hierbei zunchst alle zueinander passenden Seiten beider Bcher nebeneinander legen, um anschlieend doch nur eine handvoll Seiten herauszufiltern, in denen der gesuchte Begriff berhaupt vorkommt ? Wohl kaum, vielmehr, so denke ich, wrden Sie entweder zunchst in beiden Bchern getrennt mit Hilfe des Index die gesuchten Seiten heraussuchen und diese anschlieend zusammenmischen. Oder Sie wrden zunchst nur die Seiten eines Buches mit Hilfe des Index durchsuchen, dann aber bei jeder gefundenen Seite sofort die passenden Seiten des zweiten Buches heraussuchen und dazulegen. So pragmatisch dieses Beispiel auch klingen mag, das Datenbanksystem arbeitet in einer hnlichen Weise, wobei in der Tat beide Verfahrensweisen zum Tragen kommen knnen. Das in der Tabelle 3.7 angedeutete kartesische Produkt ist eigentlich nur Teil des mathematischen Modells, das den relationalen Datenbank zugrunde liegt. In der Regel versucht das Datenbanksystem dessen Erzeugung zu umgehen, da ansonsten bei groen Tabellen der Abfragegau droht (die Session hngt mal wieder). In unserem Beispiel knnte die Datenbank vielleicht wirklich zunchst eine der beiden Tabellen (z.B. Personalien) lesen, um anschlieend fr jede Personalnummer die passenden Datenstze aus den Gehaltsdaten zu der logischen Tabelle hinzuzufgen. Das dies wirklich so passiert und wie man das Ganze vielleicht sogar steuern kann, dazu erhalten Sie allerdings erst spter im Abschnitt Tuning von Abfragen mehr Informationen. Im nchsten Schritt wollen wir die verschiedenen mglichen Verknpfungsformen zunchst einmal katalogisieren und dabei auch deren Verwendung mit Hilfe geeigneter Beispiele erklren.

3.2.1

Inner-Joins

Ich habe lange ber die berschrift dieses Abschnittes nachgedacht. Das was ich im Folgenden beschreiben mchte und die sicherlich meistverwendete Verknpfung darstellt, wird selbst in der deutschsprachigen Literatur zunchst einmal als Join (engl. = verbinden, vereinigen) bezeichnet, wobei dieses Wrtchen allerdings dann auch wieder schon das einzige ist, was die verschiedenen berschriften gemeinsam haben. Konkret ist da von Inner-Joins, Equi-Joins, Theta-Joins, Natural-Joins oder

Verknpfungen

269

Semi-Joins die Rede, wobei sich hinter diesen Begriffen eigentlich immer das gleiche oder zumindest etwas sehr hnliches verbirgt. Wie Sie sehen, habe ich mich letztendlich fr die berschrift Inner-Joins entschieden, weil sie letztendlich wenigstens zur berschrift des bernchsten Kapitels Outer-Joins passt, fr die mir beim besten Willen nichts Besseres eingefallen ist. Zunchst einmal wird bei einem Join innerhalb einer Abfrage mehr als eine Tabelle in der from-Klausel verwendet und zum anderen werden die zusammengehrenden Felder in der where-Bedingung der Abfrage mit einem Gleichheitszeichen verbunden. Ich mchte es im Folgenden auch bei dieser groben Aufteilung belassen und nicht auf weitere Feinheiten eingehen, die sich vor allem aus der Betrachtung des Abfrageergebnisses her ergeben. Uns ist es also egal, ob im Abfrageergebnis nur Spalten aus einer der beteiligten Tabellen verwendet werden oder ob die Verknpfung zu einer logischen Verlngerung der anderen Tabelle fhrt. In jedem Fall werden, wie schon in der Einleitung zu diesem Thema erlutert, mehrere Tabellen in der from-Klausel der Abfrage aufgezhlt und anschlieend erfolgt im Rahmen der where-Klausel die voll- oder teilweise Verbindung der gemeinsamen Felder. In unserem folgenden Beispiel verbinden wir die Stammdatentabellen Personalien, Beschftignungsverhltnisse und Gehlter zu einem logischen Datensatz, aus dem wir verschiedene Informationen bentigen.
select a.persnr, substr(a.name,1,10), b.lfdnr, c.gab, c.gehalt from gehalt c, bvs b, personalien a where b.persnr = a.persnr and c.persnr = b.persnr and c.lfdnr = b.lfdnr

Wie Sie schon an dem kleinen Beispiel erkennen knnen, entstehen durch die Verknpfung von Tabellen rasch komplexe where-Bedingungen, die wenn Sie unvollstndig bzw. fehlerhaft kodiert werden zu umfangreichen und vor allem falschen Abfrageergebnissen fhren. Aus diesem Grund ist man meiner Ansicht nach gut beraten, wenn man beim Erstellen solcher Abfragen auch eine gewissen gestalterische Komponente bercksichtig. Betrachten Sie im Vergleich doch einfach mal das folgende Beispiel, dass technisch gesehen bzw. vom Ergebnis her betrachtet der eben gezeigten Abfrage entspricht.
select a.persnr, substr(a.name,1,10), b.lfdnr, c.gab, c.gehalt from gehalt c, personalien a, bvs b where b.lfdnr = c.lfdnr and a.persnr = b.persnr and c.persnr = b.persnr

In einem solchen Dickicht kann man durchaus auch mal eine Verknpfung vergessen oder falsch verbinden. Msste ich in einer solchen Abfrage nach Fehlern suchen oder sie erweitern, dann bestnde meine erste Aktion darin, diese zu entflechten. Ich habe mir in den letzten Jahren folgende stilistische Vorgehensweise angewhnt:

270

Abfragen

: : :

Verwenden Sie innerhalb der from-Klausel fr jede Tabelle eine eigene Zeile und vergeben Sie fr jede Tabelle einen Aliasnamen, den Sie anschlieend bei allen verwendeten Feldnamen konsequent verwenden. Erstellen Sie ebenfalls fr jede where-Bedingung eine eigene Zeile. Hierbei habe ich mir ebenfalls angewhnt, die logischen Verknpfungsoperatoren an den Anfang der Zeile zu schreiben und die ganze Struktur bei notwendigen Schachtelungen entsprechend einzurcken. Bemhen Sie sich, die Verknpfungsbedingungen der einzelnen Tabellen am Stck bzw. aneinanderhngend zu kodieren.

Nur selten ist es Absicht, fr die verwendeten Tabellen nur unvollstndige oder sogar gar keine Verbindungsbedingungen zu programmieren, um damit den Vervielfltigungseffekt des kartesischen Produkts zu erhalten. In jedem Fall knnen Sie beim erstmaligen Test Ihrer Abfrage eine zustzliche Bedingung hinzufgen, um die maximale Gre der Ergebnismenge einzuschrnken.
and rownum < 100

Mit Hilfe der Pseudospalte rownum werden die Zeilen der Ergebnismenge durchgezhlt, wobei Sie diese Spalte auch innerhalb einer where-Bedingung verwenden knnen, um die Anzahl der von der Abfrage gelieferten Datenstze einzuschrnken. Das folgende Beispiel wrde, wenn wir statt count irgendwelche konkreten Spalten in der select-Anweisung verwenden wrden, genau 37536 Ausgabestze erzeugen und somit schon etwas Geduld von uns abverlangen.
SQLWKS> select count(*) 2> from personalien a, 3> bvs b, 4> gehalt c; COUNT(*) ---------37536 1 row selected.

Dagegen wird die Datensatzmenge im Folgenden durch den Einsatz des Feldes rownum so oder so auf 99 begrenzt.
SQLWKS> select count(*) 2> from personalien a, 3> bvs b, 4> gehalt c 5> where rownum < 100; COUNT(*) ---------99 1 row selected.

Verknpfungen

271

3.2.2

Unterabfragen

Unterabfragen sind eine spezielle Form der Tabellenverknpfung, bei der im Rahmen einer Auswahlbedingung innerhalb der where-Bedingung Daten aus einer anderen Tabelle abgefragt werden. Hierbei gibt es im Prinzip zwei Varianten. Bei der einen Variante wird mit Hilfe der Unterabfrage lediglich die Existenz eines bestimmten Datensatzes ermittelt, wohingegen bei der anderen Variante ein konkretes Ergebnis abgerufen wird, das beispielsweise innerhalb der Auswahlbedingung mit einem Wert oder anderem Feld verglichen wird. Existenzprfung Nehmen wir einmal an, wir stnden folgender Aufgabenstellung gegenber: Wir sollen die Namen aller Mitarbeiter ermitteln, die im Jahr 1998 die Lohnarten 300 bis 350, erhalten haben. Dabei interessieren wirklich nur die Namen, d.h. die konkreten Betrge oder Auszahlungsmonate interessieren nicht. Ebenfalls ist nicht wichtig, in welchem Beschftigungsverhltnis die Lohnarten gezahlt wurden. Mit den bisher beschriebenen Methoden knnten Sie diese Aufgabenstellung folgendermaen lsen.
SQLWKS> 2> 3> 4> 5> 6> 7> select distinct a.name from personalien a, lohnarten b where b.persnr = a.persnr and b.gab = to_date('01.01.1998','DD.MM.YYYY') and b.la between '300' and '350' order by a.name;

NAME -------------------------------------------------Beckmann,Yonne Bruckner,Yonne Btzing,Brbel Calvo,Ulrike ... Sistermann,Willy Voltair,Samuel Zola,Wolf 16 rows selected.

In dieser Abfrage werden die Tabellen personalien und lohnarten ber das gemeinsame Feld persnr miteinander verknpft. Auerdem wird der Zugriff auf die Abrechnungsergebnisse durch zwei weitere Auswahlbedingungen auf die gewnschten Lohnarten und das bentigte Jahr eingeschrnkt. Das Problem bei dieser Selektion ist aber, dass meistens nicht nur eine der gesuchten Lohnarten, sondern oft mehrere oder sogar alle Lohnarten fr einen Mitarbeiter in den Abrechnungsergebnissen vorhanden sind. Aus diesem Grund wrde jeder Name mehrfach gelistet werden, wenn wir die Abfrage ohne die distinct-Klausel starten wrden.

272

Abfragen

In einer solchen Konstellation kann es, vor allem wenn die Grenrelationen der beteiligten Tabellen extrem unterschiedlich sind (z.B. personalien 50.000 und lohnarten > 4 Mio. Datenstze), sinnvoll sein, statt der gewhnlichen Verknpfung die Existenz der gesuchten Lohnarten mit Hilfe einer Unterabfrage zu ermitteln und diese Existenz als Auswahlkriterium fr die Namensselektion zu verwenden.
SQLWKS> 2> 3> 4> 5> 6> 7> 8> 9> select a.name from personalien a where exists(select 1 from lohnarten b where b.persnr = a.persnr and b.gab = to_date('01.01.1998','DD.MM.YYYY') and b.la between '300' and '350' ) order by a.name;

NAME -------------------------------------------------Beckmann,Yonne Bruckner,Yonne Btzing,Brbel Calvo,Ulrike ... Sistermann,Willy Voltair,Samuel Zola,Wolf 16 rows selected.

Mit Hilfe des Schlsselwortes exists knnen Sie innerhalb der where-Bedingung eine besondere Auswahlbedingung erzeugen, die auf einer Unterabfrage basiert. Diese gesamte Unterabfrage wird hinter dem exists-Kommando in Klammern programmiert und einmal abgesehen von der sehr sprlichen select-Klausel kann die Unterabfrage alle Elemente einer gewhnlichen Abfrage enthalten, d.h. Sie knnen auch in der Unterabfrage wiederum mehrere Tabellen verwenden, diese in gewohnter Weise miteinander verknpfen oder sogar wieder eine weitere Unterabfrage einbauen, d.h. die Unterabfragen knnen grundstzlich in beliebiger Tiefe geschachtelt werden. Auerdem haben Sie in jeder Unterabfrage Zugriff auf alle Felder der darber liegenden Abfragen. Was Sie bei einer exists-Unterabfrage so genau abfragen ist eigentlich egal, denn das in der select-Klausel genannte Feld wird von der Datenbank sowieso nicht geliefert. Stattdessen wird wirklich nur die Existenz der spezifizierten Auswahl geprft, wobei die exists-Klausel bei Erfolg den Wahrheitswert wahr und ansonsten eben falsch liefert. Aus diesem Grund finden Sie bei derartigen Abfragen oftmals gar kein Feld in der select-Anweisung, sondern so wie in unserem Beispiel wird einfach irgendeine Konstante verwendet.

Verknpfungen

273

Nichtexistenz prfen Etwas Vorhandenes zu selektieren war ja eigentlich noch nie besonders schwierig, ganz gleich, ob man es auf die eine oder andere Art erledigt. Die wahre Strke der exists-Klausel offenbart sich manchmal erst, wenn es darum geht das Nichtvorhandene auszuwhlen, was man mit Hilfe der exists-Auswahlbedingung ebenfalls prima bzw. einfach erledigen kann. Im Unterschied zur eben beschriebenen Aufgabenstellung geht es diesmal darum, nur die Mitarbeiter zu selektieren, die im Jahr 1998 die genannten Lohnarten nicht erhalten haben. Wie Sie an dem folgenden Beispiel sehen, ist das mit exists wirklich ganz einfach, denn aus diesem Befehl wird einfach not exists, um die Abfrageumkehrung durchzufhren. Ansonsten ndert sich in Bezug auf die Verwendung oder die zu beachtenden Regeln gar nichts.
SQLWKS> select a.name 2> from personalien a 3> where not exists(select 1 4> from lohnarten b 5> where b.persnr = a.persnr 6> and b.gab =t o_date('01.01.1998','DD.MM.YYYY') 7> and b.la between '300' and '350' 8> ) 9> order by a.name; NAME -------------------------------------------------Frisch,Berta Hardt,Andreas Heiden,Magareta ... Voltair,Samuel Voltair,Samuel 8 rows selected.

Einen Wert selektieren Die dritte Variante der Unterabfrage besteht darin, diesmal wirklich einen bzw. eine Menge von Werten aus den abgefragten Tabellen zurckzuliefern. Zur Demonstration kehre ich zunchst einmal zum ersten Lohnartenbeispiel zurck und zeige Ihnen hier gleich noch eine weitere Variante, wie Sie die Abfrage durchfhren knnten.
SQLWKS> 2> 3> 4> 5> 6> 7> 8> select a.name from personalien a where persnr in (select persnr from lohnarten b where b.gab=to_date('01.01.1998','DD.MM.YYYY') and b.la between '300' and '350' ) order by a.name;

274

Abfragen

NAME -------------------------------------------------Beckmann,Yonne Bruckner,Yonne Btzing,Brbel Calvo,Ulrike ... Sistermann,Willy Voltair,Samuel Zola,Wolf 16 rows selected.

Um eines vorwegzunehmen: wenn Sie solche Aufgabenstellungen auf diese Weise lsen, dann werden Sie unter Ihren Datenbankadministratoren schnell neue Freunde finden. Wie schn, dass es im Rahmen eines solchen Buches manchmal einfach nur darum geht, die vorhandenen Mglichkeiten und Varianten aufzuzeigen. Die verwendete Unterabfrage liefert zunchst die Menge aller Personalnummern, die innerhalb der Lohnartentabelle die bekannten Kriterien erfllen. Das knnen im richtigen Leben ein paar hunderttausend Nummern sein, die zunchst einmal bestenfalls im Hauptspeicher aber wahrscheinlich eher in einer temporren Hilfstabelle gespeichert werden. Anschlieend kommt die uere Abfrage auf die Tabelle der Personalien zum tragen, wobei jetzt jede Personalnummer wegen des in-Vergleichoperators mit der temporren Tabelle abgeglichen wird. Ist die Personalnummer dort vorhanden, dann wird der Name des Mitarbeiters in die Ergebnismenge kopiert. In der Praxis sollten Sie Unterabfragen, die Mengen von Daten liefern, nur mit Bedacht einsetzen, was im brigen sowieso nur zusammen mit dem in-Operator funktioniert. Bei allen anderen Vergleichsoperatoren darf Ihre Unterabfrage nur genau einen Wert zurckliefern, was wie wir noch sehen werden, oftmals besondere Anforderungen an die Programmierung solcher Unterabfragen stellt.
select a.name from personalien a where persnr = (select distinct persnr from lohnarten b where b.persnr = a.persnr and b.gab = to_date('01.01.1998','DD.MM.YYYY') and b.la between '300' and '350' ) order by a.name;

Da ein Mitarbeiter meistens mehrer Datenstze in der Lohnartentabelle besitzt, kann innerhalb der Unterabfrage zunchst nicht garantiert werden, dass sie nur einen Wert zurckliefert. In jedem Fall wrde sie zwar nur genau eine Personalnummer liefern, diese aber vielleicht fnf oder sechsmal, weil der Mitarbeiter fnf oder sechs der gesuchten Lohnarten besitzt. Aus diesem Grund habe ich in der select-Klausel der Unterabfrage zunchst einmal das Schlsselwort distinct verwendet, um die Ergebnismenge hierdurch auf einen einzigen Wert zu reduzieren.

Verknpfungen

275

Allerdings ist das nicht das Gelbe vom Ei, denn wie Sie noch sehen werden, hilft das distinct-Kommando nur in Ausnahmefllen. Besser Sie gewhnen sich im Zusammenhang solcher Unterabfragen gleich an die Verwendung einer Aggregatfunktion, um die Ergebniseindeutigkeit zu erzwingen. Die beiden Funktionen min oder max sind hierfr beispielsweise bestens geeignet.
select a.name from personalien a where persnr = (select max(persnr) from lohnarten b where b.persnr = a.persnr and b.gab = to_date('01.01.1998','DD.MM.YYYY') and b.la between '300' and '350' ) order by a.name;

Damit wre unser Lohnartenbeispiel genug strapaziert. Allerdings will ich noch einmal betonen, dass die letzten Beispiele zum Teil nur als Demonstrationsobjekt geeignet bzw. nicht zur Nachahmung empfohlen sind. Wenn es nur darum geht, im Rahmen einer Abfrage die Existenz anderer Gegebenheiten abzuprfen, dann sollten Sie in jedem Fall die exists-Variante verwenden oder ber eine ganz normale Verknpfung nachdenken, sofern die Datenmenge und die selektierten Spalten dies zulassen. Fr die wertzurckliefernden Unterabfragen gibt es allerdings auch viele sinnvolle Beispiele, fr die ich eines im folgenden demonstrieren mchte. Hierzu mssen wir uns zunchst einmal an unsere Abfrage erinnern, mit der wir einen logischen Datensatz aus Personalien, Beschftigungsverhltnisse und Gehaltshistorien gebildet hatten. Meistens hat ein Mitarbeiter innerhalb eines Beschftigungsverhltnisses mehrere Gehaltsdatenstze. Solche Historien entstehen in unserem Beispiel durch eine Versetzung (andere Kostenstelle) oder durch echte Gehaltsvernderungen. Ferner besteht auch die Mglichkeit, dass fr einen Mitarbeiter Zukunftsdaten vorhanden sind (vgl. Abb. 3.2).

Personalien 4711

BVs 0

Gehlter 01.01.1997 01.01.1998 01.04.1999 01.09.1999 01.10.2000 01.03.2001

Abbildung 3.2: Struktur der Gehaltshistorie eines Mitarbeiters

276

Abfragen

In einem solchen Fall wrden die selektierten Mitarbeiterdaten entsprechend hufig angezeigt, wobei uns in dem Fall auch kein distinct-Kommando weiterhilft, da sich die einzelnen Gehaltsdaten blicherweise unterscheiden. Vor allem besteht die Herausforderung ja vielleicht darin, die Gehaltsdaten zu einem ganz speziellen Zeitpunkt (z.B. 24.08.2000) auszuwhlen, wobei Sie nicht genau wissen, welches Datum hierbei fr den einzelnen Mitarbeiter selektiert werden muss. Betrachten Sie zusammen mit dieser Fragestellung noch einmal die Abbildung 3.2. Welcher Datensatz ist der richtige, wenn wir den aktuellen Gehaltsdatensatz zum 24.08.2000 suchen? Aus der Abbildung kann man erkennen, dass es sich in dem Beispiel um den Datensatz vom 01.09.1999 handelt. Seit diesem Termin gab es keine nderung mehr, so dass die zugehrigen Daten auch heute immer noch gltig sind. Allgemein gilt, dass wir aus der Menge aller Gehaltshistorien eines Mitarbeiters, die kleiner oder gleich unserem Stichtag sind, denjenigen Datensatz mit dem grten Gltigkeitsdatum suchen. Diesen mitarbeiterindividuellen Termin wollen wir nun mit Hilfe einer Unterabfrage ermitteln und hierdurch eine Abfrage mit aktuellen Gehaltsdaten erzeugen. Dabei verzichten wir allerdings auf das konstante Stichtagsdatum und verwenden stattdessen die Funktion sysdate, so dass unserer Abfrage tagesaktuelle Gehaltshistorien selektiert.
SQLWKS> select a.persnr, substr(a.name,1,10), b.lfdnr, c.gab, c.gehalt 2> 3> from gehalt c, 4> bvs b, 5> personalien a 6> 7> where b.persnr = a.persnr 8> and c.persnr = b.persnr 9> and c.lfdnr = b.lfdnr 10> and c.gab = (select max(gab) 11> from gehalt c1 12> where c1.persnr = c.persnr 13> and c1.lfdnr = c.lfdnr 14> and c1.gab <= sysdate 15> ) 16> PERSNR SUBSTR(A.N LFDNR GAB GEHALT ----------- ---------- ---------- -------------------- ---------7000002 Karlo,Armi 0 01-APR-99 4980 7000003 Heiden,Mag 0 01-AUG-99 6500 7000004 Hardt,Andr 0 01-APR-99 7850 7000005 Nibelungen 0 01-SEP-99 6500 7000006 Beckmann,Y 0 01-AUG-99 5899 7000007 Calvo,Ulri 0 01-JAN-99 6500 ... 7000008 Voltair,Sa 0 01-JAN-98 4750 7000008 Voltair,Sa 1 01-MAR-98 5200 34 rows selected.

Verknpfungen

277

Wie funktioniert diese Abfrage nun genau? Betrachten wir hierzu zunchst noch einmal den ueren Teil der Selektion. Mit Hilfe der Zeilen sieben bis neun werden die gemeinsamen Felder der drei beteiligten Tabellen miteinander verknpft. Ohne weitere Auswahlbedingungen wrden wir damit wieder fr jeden Mitarbeiter alle vorhandenen Gehaltshistorien erhalten. Da wir aber immer nur genau eine Historie mit einem bestimmten gltig-ab-Datum wnschen, mssen wir hierfr ein zustzliches Auswahlkriterium definieren.
and c.gab = <irgend ein Datum>

Das Problem dabei ist nur, dass der aktuell gltige Gehaltsdatensatz fr jeden Mitarbeiter ein individuelles gltig-ab-Datum besitzt. Aus diesem Grund knnen wir das Feld c.gab nicht mit irgendeiner Datumskonstante vergleichen, denn wir kennen den konkreten Wert nicht; wir kennen lediglich die Regel den Vergleichswert zu bestimmen. Betrachten wir nun als Nchstes die im inneren Teil programmierte Unterabfrage.
SQLWKS> 2> 3> 4> 5> select gab from gehalt c1 where c1.persnr = '7000002' and c1.lfdnr = 0 and c1.gab <= sysdate;

GAB -------------------01-APR-98 01-APR-99 2 rows selected.

Die Abfrage liefert fr eine konkrete Personalnummer und das entsprechende Beschftigungsverhltnis alle gltig-ab-Daten des Gehaltsdatensatzes, die kleiner oder gleich dem aktuellen Tagesdatum sind. Von diesen Datumswerten bentigen wir allerdings nur dasjenige, das dem Tagesdatum am nchsten liegt. Mit anderen Worten bentigen wir also den grten dieser Werte, den wir leicht mit Hilfe der max-Funktion ermitteln knnen. Natrlich kann die Abfrage der Personalnummer und des BVs nicht wie in dem kleinen Beispiel mit Hilfe irgendeiner Konstante erfolgen, sondern wir beziehen uns hier auf die entsprechenden Felder aus der darber liegenden Abfrage. Fr jeden in der ueren Abfrage selektierten Datensatz wird also die Unterabfrage gestartet, die anschlieend das bentigte Datum zurckliefert, mit dem der richtige Gehaltsdatensatz ausgewhlt wird. Sie knnen sich diese Unterabfrage auch als eine Art virtuelle Funktion vorstellen. In unserem Fall bekommt diese virtuelle Funktion die Parameter c.persnr und c.lfdnr bergeben und liefert als Ergebnis das gesuchte Historiendatum.

278

Abfragen

3.2.3

Outer-Joins

Bei den bisherigen Verknpfungen wurden im Ergebnis immer nur diejenigen Datenstze gezeigt, bei denen fr die verknpften Felder in allen Tabellen entsprechende Werte bzw. Stze vorhanden waren. Das kann manchmal zu unerwnschten Verlusten von Informationen fhren, weshalb es fr solche Flle entsprechende Abfragealternativen gibt. Betrachten Sie hierzu zunchst einmal die folgende kleine Abfrage auf unserer Lndertabelle.
SQLWKS> select * from laender; LAN B BEZEICHNUNG --- - -----------------------------DEU Y Deutschland AUT Y sterreich BEL N Belgien GBR N Grossbritannien FIN N Finnland FRA N Frankreich 6 rows selected.

Wie Sie dem Beispiel entnehmen knnen, enthlt unsere Lndertabelle genau sechs verschiedene Datenstze. Verknpfen wir nun im Anschluss diese Tabelle mit den Personalien, dann erhalten wir allerdings nur noch folgendes Ergebnis.
SQLWKS> select distinct b.land, b.bezeichnung 2> from personalien a, 3> laender b 4> where b.land = a.land; LAN BEZEICHNUNG --- -----------------------------DEU Deutschland 1 row selected.

Durch die Verknpfung sind uns insgesamt fnf Lnder verloren gegangen, was ganz einfach daran liegt, dass keiner unserer Mitarbeiter aus einem der dort gespeicherten Lnder stammt. Allerdings knnen wir auf diese Weise die Antwort auf die Frage nach allen verfgbaren Lndern und den jeweils zugeordneten Mitarbeitern nicht in einem Zug beantworten. Natrlich gibt es eine Lsung fr dieses Dilemma, die in eine besondere Form der Abfragetechnik mndet. Mit Hilfe der sogenannten Outer-Joins haben Sie die Mglichkeit, die in der verknpften Tabelle fehlenden Datenstze durch imaginre Nullwerte aufzufllen. Wie Sie an dem letzten Satz erkennen knnen, steht uns beim Outer-Join also immer ein kleines Entscheidungsproblem ins Haus, denn wir mssen festlegen, welches quasi die fhrende Tabelle ist bzw. fr welche Tabelle die eventuell fehlenden Datenstze automatisch ergnzt werden sollen.

Verknpfungen

279

SQLWKS> select b.land, b.bezeichnung, a.name 2> from personalien a, 3> laender b 4> where b.land = a.land (+); LAN BEZEICHNUNG --- -----------------------------AUT sterreich BEL Belgien DEU Deutschland DEU Deutschland DEU Deutschland ... DEU Deutschland FIN Finnland FRA Frankreich GBR Grossbritannien 26 rows selected. NAME --------------------------

Beckmann,Yonne Bruckner,Yonne Btzing,Brbel Zola,Wolf

In der Abfrage wird die aufzufllende bzw. unvollstndige Tabelle mit Hilfe der Zeichen (+) markiert, d.h. konkret mssen Sie diese Zeichenfolge in der where-Bedingung hinter jedes Feld aus der Tabelle schreiben. Dabei ist es gleichgltig, ob das Feld im Rahmen der Tabellenverknpfung oder in einer anderen Auswahlbedingung verwendet wird. Dies wird sicherlich klarer, wenn wir unsere Beispielabfrage noch einmal erweitern. Wir mchten wie bisher alle Lnder und die zugehrigen Mitarbeiter selektieren, dabei interessieren uns die Namen aber nur dann, wenn die Namen der Mitarbeiter zwischen B und F liegen.
SQLWKS> select b.land, b.bezeichnung, a.name 2> from personalien a, 3> laender b 4> where b.land = a.land (+) 5> and substr(a.name (+),1,1) between 'B' and 'F'; LAN BEZEICHNUNG --- -----------------------------AUT sterreich BEL Belgien DEU Deutschland DEU Deutschland DEU Deutschland DEU Deutschland DEU Deutschland FIN Finnland FRA Frankreich GBR Grossbritannien 10 rows selected. NAME ----------------------------

Beckmann,Yonne Calvo,Ulrike Frisch,Berta Bruckner,Yonne Btzing,Brbel

280

Abfragen

In diesem Beispiel haben wir unserer Abfrage eine weitere Auswahlbedingung mit einem Feld aus den Personalien hinzugefgt, und obwohl diese Zusatzbedingung mit der eigentlichen Tabellenverknpfung gar nichts zu tun hat, mssen Sie die Fllmarkierung (+) hinter dem Namensfeld anfgen, damit die Abfrage entsprechend funktioniert. Jetzt wird es allerdings hchste Zeit ein wenig auf die Bremse zu treten, denn das letzte Beispiel knnte vermuten lassen, dass auch innerhalb der Outer-Joins zu ziemlich alles mglich ist und geht, was aber bei weitem nicht der Fall ist. Vielmehr gibt es eine Reihe von Regeln bzw. Einschrnkungen, die ich Ihnen nicht vorenthalten mchte.

: : :

Der Operator (+) kann innerhalb der where-Klausel fr alle Spalten der in der from-Klausel verwendeten Tabellen oder Views verwendet werden. Werden zwei Tabellen mit mehr als einer Auswahlbedingung verknpft, dann muss der Operator (+) in allen diesen Auswahlbedingungen verwendet werden. Der Outer-Join-Operator (+) kann nur direkt hinter einem Spaltennamen verwendet werden. Die Benutzung hinter einem Ausdruck ist nicht mglich, d.h. die nachfolgende Verwendung ist beispielsweise nicht zulssig.
substr(a.name, 1, 20) (+) between 'B' and 'F'

: : :

Der Operator (+) kann nicht in einer Auswahlbedingung verwendet werden, die mit einer or-Bedingung verknpft wurde. Ebenfalls nicht mglich ist die Verwendung des Outer-Join-Operators zusammen mit dem in-Vergleichsoperator. Zuletzt, und das ist nach meiner Meinung die am hrtesten treffende Einschrnkung, drfen Sie den Outer-Join auch nicht zusammen mit einer Unterabfrage verwenden, d.h. das nachfolgende Beispiel ist ebenfalls unzulssig.
select a.persnr, substr(a.name,1,10), b.lfdnr, c.gab, c.gehalt from gehalt c, bvs b, personalien a where b.persnr = a.persnr and c.persnr (+) = b.persnr and c.lfdnr (+)= b.lfdnr and c.gab (+) = (select max(gab) from gehalt c1 where c1.persnr = c.persnr and c1.lfdnr = c.lfdnr and c1.gab <= sysdate );

Die letzte der eben genannten Restriktionen kann in der Tat zu einem echten Problem fhren. Erinnern Sie sich noch einmal an unser Beispiel zur Selektion der aktuellen Gehaltshistorie. Diese Abfrage lieferte fr jeden Mitarbeiter den aktuellen

Verknpfungen

281

Gehaltsdatensatz, allerdings mit der Nebenwirkung, dass er aus der Selektion vollstndig herausfllt, wenn der Mitarbeiter diesen aktuellen Datensatz nicht besitzt. Das wre zum Beispiel der Fall, wenn aus irgendwelchen Grnden noch kein Gehaltsdatensatz angelegt wurde oder wenn der erste Datensatz hinter dem aktuellen Tagesdatum liegt. Wenn Sie sichergehen wollen bzw. mssen, dass Ihre Abfrage auch solche Datenstze selektiert, dann knnen Sie das mit Hilfe einer der im nchsten Abschnitt beschriebenen Mengenoperationen erreichen.

3.2.4

Mengenoperationen

Neben den bisher beschriebenen Mglichkeiten, eine einzelne Abfrage mit Hilfe verschiedener Verknpfungen zu gestalten, sind Sie des weiteren auch in der Lage, die Ergebnisse verschiedener einzelner Abfragen quasi zu einer gesamten Ausgabemenge zusammenfhren. Die bisher behandelten Operatoren bezogen sich also immer auf eine einzelne Abfrage, wohingegen die im Folgenden beschriebenen Operatoren zur Verknpfung verschiedener Abfrageergebnisse dienen. Insgesamt bietet Oracle Ihnen die in der nachfolgenden Tabelle aufgefhrten Operatoren, um die Ergebnisse zweier oder mehrerer Abfragen zu verbinden.
Operator union Beschreibung fhrt zur Vereinigungsmenge der Ergebnisse der beiden verknpften Abfragen, d.h. die Ausgabemenge enthlt keine doppelten Datenstze. mischt die Ergebnisse der beiden verknpften Abfragen. Das Ergebnis enthlt nur diejenigen eindeutigen Datenstze, die jeweils auch in den beiden einzelnen Abfrageergebnissen enthalten sind. Mit diesem Operator erhalten Sie diejenigen eindeutigen Datenstze, die in der ersten aber nicht in der zweiten Abfrage enthalten sind, d.h. das Ergebnis entspricht dem distinct-Ergebnis der ersten Abfrage abzglich aller Datenstze, die von der zweiten Abfrage geliefert werden.

union all intersect

minus

Tabelle 3.8: bersicht der Mengenoperatoren

Die einzelnen Mengenoperatoren haben alle die gleiche Rangfolge, d.h. wenn mehr als zwei Abfragen miteinander verknpft werden, dann erfolgt die Auswertung entsprechend der Reihenfolge des Auftretens der jeweiligen Operatoren.
SQLWKS> 2> 3> 4> 5> 6> 7> select persnr from personalien union select persnr from bvs minus

282

Abfragen

8> 9> select persnr from gehalt; PERSNR ----------7000088 1 row selected.

Ist diese natrliche Reihenfolge nicht gewnscht, dann knnen bzw. mssen Sie die mit Hilfe von Klammern verndern.
SQLWKS> 2> 3> 4> 5> 6> 7> 8> 9> 10> select persnr from personalien union ( select persnr from bvs minus select persnr from gehalt );

PERSNR ----------7000001 7000002 7000003 7000088 7000188 24 rows selected.

Neben diesen einfachen Regeln, mssen Sie bei der Verwendung der eben genannten Mengenoperatoren eigentlich nur noch beachten, dass zum einen vielleicht einmal abgesehen von den Operatoren union bzw. union all die Verwendung dieser mchtigen Verknpfungswerkzeuge ihren Tribut in entsprechender Rechenleistung bzw. Verarbeitungszeit zollt und zum anderen die mit Mengenoperatoren verknpften Abfragen alle keine eigene order by-Klausel besitzen. Dahingegen verfgt die gesamte Abfrage bei Bedarf am Ende ber eine eigene Sortieranweisung in Form des blichen order by-Kommandos.
SQLWKS> 2> 3> 4> 5> 6> 7> 8> select persnr from personalien union select persnr from bvs minus

Verknpfungen

283

9> select persnr from gehalt 10> order by persnr; PERSNR ----------7000088 1 row selected.

Die zuletzt genannte Restriktion ist eigentlich auch ziemlich naheliegend, denn warum sollte jedes einzelne Abfrageergebnis nach irgendwelchen Kriterien sortiert werden, wenn diese Sortierung nach dem Ausfhren der spezifizierten Verknpfung in Bezug auf das Endergebnis berhaupt keine Relevanz mehr hat. Im richtigen Leben erhlt man beim Mischen von pfeln und Birnen leckeren Obstsalat. Was beim Vermischen verschiedener Abfrageergebnisse am Ende dabei herauskommt, darauf kann das Datenbanksystem natrlich nicht achten. Das Einzige, was Oracle im Zusammenhang mit den Mengenoperatoren prft, ist die bereinstimmung der Datentypen fr die entsprechenden Spalten der einzelnen Abfragen. Auf den Rest mssen Sie natrlich selber achten, d.h. liefert die erste Abfrage als zweite Spalte Straen und die zweite Abfrage in dieser Spalte Orte, dann erhalten Sie als Endergebnis logischerweise genau diesen zubereiteten Abfragesalat. Nach dieser kurzen Einfhrung, werden wir die verschiedenen Mengenoperatoren in den folgenden Abschnitten nun noch etwas nher unter die Lupe nehmen. Der union-Operator Mit Hilfe des Operators union knnen Sie die Ergebnismengen zweier Abfragen mischen (vereinigen). Dabei handelt es sich in der Tat wie in der Schulmathematik um die Erstellung einer Vereinigungsmenge, denn das gelieferte Ergebnis enthlt keine doppelten Elemente, d.h. der union-Operator verbindet die beiden Ergebnisse mit einer Art distinct-Klausel. Ist die Eliminierung doppelter Datenstze nicht erwnscht, dann mssen Sie anstelle des union-Operators die besondere Variante union all verwenden, bei der die beiden Abfrageergebnisse einfach gemischt werden. In Bezug auf die interne Verarbeitung gilt brigens auch hier das Gleiche, was ich schon in Bezug auf das Schlsselwort distinct gesagt habe. Die Vermischung zweier Abfrageergebnisse ist naheliegenderweise weniger aufwendig, als die zustzliche Erzwingung eindeutiger Abfrageergebnisse, d.h. wenn Sie wissen, dass alle Ihre verwendeten Teilabfragen ausschlielich ergnzenden Charakter haben, dann sollten Sie den Operator union all verwenden. Erinnern wir uns noch einmal an unser Beispiel zur Ermittlung der aktuellen Gehaltsdatenstze, bei dem die jeweils aktuellen Werte mit Hilfe einer Unterabfrage selektiert wurden. Diese Abfrage liefert Ihnen bei Verwendung der auf der CD enthaltenen Beispieldaten genau 34 Datenstze. Wie Sie weiterhin der folgenden Abfrage entnehmen knnen, existiert in unserer kleinen Beispieldatenbank ein Datensatz, dessen erster und einziger Datensatz ab dem 01.01.2007 gltig ist.
SQLWKS> select gab, gehalt 2> from gehalt

284

Abfragen

3> where persnr = '7000188' 4> GAB GEHALT -------------------- ---------01-JAN-07 6240 1 row selected.

Dies ist im brigen der einzige Datensatz, der zumindest in nchster Zeit erst nach dem aktuellen Tagesdatum gltig wird, so dass die zugehrige Personalnummer als einzige nicht in unserer tagesaktuellen Gehaltsabfrage enthalten ist. Mit Hilfe des union-Operators knnen Sie die Abfrage nun leicht so erweitern, dass sie zum einen alle aktuellen Gehlter aber zum anderen fr diejenigen Mitarbeiter, die noch keinen aktuellen Gehaltsdatensatz besitzen, wenigstens bestimmte Rumpfdaten liefert.
SQLWKS> 2> 3> 4> 5> 6> 7> 8> 9> 10> 11> 12> 13> 14> 15> 16> 17> 18> 19> 20> 21> 22> 23> 24> 25> 26> 27> 28> 29> 31< select a.persnr, substr(a.name,1,10), b.lfdnr, c.gab, c.gehalt from gehalt c, bvs b, personalien a where and and and b.persnr = a.persnr c.persnr = b.persnr c.lfdnr = b.lfdnr c.gab = (select max(gab) from gehalt c1 where c1.persnr = c.persnr and c1.lfdnr = c.lfdnr and c1.gab <= sysdate )

union all select a.persnr, substr(a.name,1,10), b.lfdnr, sysdate+1, 0 from bvs b, personalien a where b.persnr = a.persnr and not exists(select 1 from gehalt c where c.persnr=b.persnr and c.lfdnr = b.lfdnr and c.gab <= sysdate );

PERSNR SUBSTR(A.N LFDNR GAB GEHALT ----------- ---------- ---------- -------------------- ----------

Verknpfungen

285

7000001 Frisch,Ber 7000002 Karlo,Armi 7000003 Heiden,Mag ... 7000022 Keun,Monik 7000188 Schmidt,Ul 35 rows selected.

0 01-JAN-90 0 01-APR-99 0 01-AUG-99 0 01-MAR-99 0 31-AUG-00

4500 4980 6500 5700 0

Der erste Teil dieser union-Abfrage entspricht unserer schon bekannten Gehaltsabfrage und liefert damit wieder den zum Tagesdatum aktuellen Gehaltsdatensatz. Der zweite Teil ab Zeile 19 ermittelt wiederum mit Hilfe einer Unterabfrage vom Typ not exists genau diejenigen Datenstze, die zum aktuellen Tagesdatum keinen Gehaltsdatensatz besitzen. Beide Einzelabfragen werden mit dem union-Operator vermischt, so dass Sie als Endergebnis dennoch fr jeden Mitarbeiter einen Datensatz geliefert bekommen. Mit Hilfe der zweiten select-Anweisung (Zeile 19) selektieren wir fr die nicht vorhandenen Gehaltsdatenstze irgendwelche Standardwerte. Dabei verwenden wir fr das Gltigkeitsdatum den Ausdruck sysdate + 1 (=morgen), so dass wir bei der Verarbeitung der Abfrageergebnisse, beispielsweise innerhalb eines Programms, die Ergebnisse der zweiten Abfrage leicht erkennen knnten. Aufgrund der Struktur der beiden Teilabfragen, knnen die oben selektierten Mitarbeiter niemals in der zweiten Abfrage auftauchen, was auch umgekehrt entsprechend gilt. Aus dem Grund vermischen wir die beiden Abfrage in Zeile 17 mit dem Operator union all. Natrlich wrde der union-Operator zum gleichen Ergebnis fhren, wre in der internen Verarbeitung aber etwas aufwndiger. Der intersect-Operator Kehren wir noch einmal kurz zur Schulmathematik zurck und erinnern uns, dass es neben den Vereinigungsmengen noch etwas anderes nmlich die Schnittmengen gab. Folglich finden Sie im Befehlsvorrat des Oracle-Sprachumfangs auch hierfr einen Mengenoperator, mit dem Sie als Ergebnis der verknpften Einzelabfragen nur diejenigen Datenstze erhalten, die auch in beiden Einzelabfragen enthalten sind, wobei das Endergebnis immer nur eindeutige Datenstze enthlt, d.h. zusammen mit dem insersect-Operator erhalten Sie fr das Gesamtergebnis immer automatisch den distinct-Effekt. Ich muss zugeben, dass ich diesen Operator in meiner bisherigen beruflichen Praxis noch nie verwendet habe. Das mag daran liegen, dass man viele denkbare Anwendungsbeispiele auch mit Hilfe entsprechender Unterabfragen und damit in einer einzigen Abfrage realisieren kann. Deshalb fllt mir hier und jetzt, zumindest unter Bercksichtigung der in unserer Beispieldatenbank vorhandenen Objekte, auch nur ein banales Beispiel ein, das lediglich die formale Anwendung des Operators demonstriert und ansonsten keinen besonderen sinnlichen Nhrwert enthlt.
SQLWKS> select a.persnr, b.lfdnr 2> from personalien a, 3> bvs b

286

Abfragen

4> 5> 6> 7> 8> 9>

where b.persnr=a.persnr intersect select persnr, lfdnr from gehalt;

PERSNR LFDNR ----------- ---------7000001 0 7000002 0 7000003 0 ... 7000188 0 35 rows selected.

Mit diesem Beispiel untersuchen wir unsere Datenstruktur und ermitteln alle vollstndigen Stammdatenstze, d.h. wir selektieren alle Personalnummern, die wenigstens ein Beschftigungsverhltnis und mindestens einen zugehrigen Gehaltsdatensatz besitzen. Natrlich htten Sie die zweite mit intersect verknpfte Abfrage auch in der Ersten als exists-Unterabfrage einbauen knnen. Trotzdem liefert der letzte Satz den Baustoff fr die Brcke hin zu einer sinnvollen Verwendungsmglichkeit. Die ist aus meiner Sicht beispielsweise immer dann gegeben, wenn die Unterabfrage zu komplex wird, zum Beispiel weil die in der Unterabfrage notwendige Existenzprfung wegen des Fehlens eines eindeutigen Schlssels nur durch Vergleich aller vorhandenen Spalten mglich wre. In dem Fall wre die Verwendung des intersect-Operators zumindest fr den Programmierer einfacher als die Kodierung entsprechender endloser and-Verknpfungen innerhalb der Unterabfrage. Der minus-Operator Mit Hilfe des minus-Operators knnen Sie von der Ergebnismenge der ersten Abfrage diejenigen Datenstze abziehen, die ebenfalls durch die zweite verknpfte Abfrage geliefert werden. Das gelieferte Endergebnis enthlt allerdings in jedem Fall keine doppelten Datenstze, d.h. die vom Datenbanksystem bereitgestellte Ergebnismenge wird quasi wie mit einem select distinct-Befehl ausgegeben. In Bezug auf die Anwendungsfhigkeit gilt aus meiner Sicht fr den minus-Operator das Gleiche, was ich schon im vorherigen Abschnitt zum intersect-Operator gesagt habe, d.h. zumindest in meiner bisherigen beruflichen Praxis hat dieser Operator bisher noch keine Rolle gespielt, da Sie das gleiche Ergebnis mit Hilfe einer Unterabfrage des Typs not exists meistens einfacher realisieren knnen. Dennoch mchte ich die Verwendung dieses Operators wieder an einem kurzen Beispiel demonstrieren. Im Kapitel Unterabfragen haben wir diejenigen Mitarbeiter selektiert, die bestimmte Lohnarten im Jahr 1998 nicht erhalten haben. Damals hatten wir dieses Ergebnis mit Hilfe einer Unterabfrage vom Typ not exists realisiert, wobei der hier beschriebene Mengenoperator natrlich noch

Verknpfungen

287

einen anderen Lsungsweg offenbart, denn die Menge der Mitarbeiter ohne die gesuchten Bezugsarten entspricht der Menge aller Mitarbeiter abzglich derjenigen, die diese Lohnarten erhalten haben.
SQLWKS> 2> 3> 4> 5> 6> 7> 8> 9> 10> 11> select a.persnr, a.name from personalien a minus select a.persnr, a.name from personalien a, lohnarten b where b.persnr = a.persnr and b.gab =to_date('01.01.1998','DD.MM.YYYY') and b.la between '300' and '350';

PERSNR NAME ----------- -------------------------------------------------7000001 Frisch,Berta 7000002 Karlo,Armin 7000003 Heiden,Magareta 7000004 Hardt,Andreas 7000008 Voltair,Samuel 7000015 Hilsamer,Kurt 7000088 Voltair,Samuel 7000188 Schmidt,Ulrike 8 rows selected.

Mit Hilfe der ersten Abfrage in den Zeilen eins bis zwei werden alle Mitarbeiter aufgelistet. Die zweite Abfrage ab Zeile sechs liefert wieder alle Mitarbeiter, die im Jahr 1998 die gesuchten Lohnarten erhalten haben. Die Verknpfung dieser beiden Abfragen erfolgt in Zeile vier mit Hilfe des minus-Operators, so dass Sie als Endergebnis nur diejenigen Namen erhalten, die diese Lohnarten eben nicht erhalten haben.

3.2.5

Hierarchische Abfragen

An dieser Stelle merkt man mal wieder deutlich, wie weit die einzelnen Datenbanksysteme in ihrem Sprachumfang trotzt Normierungsversuche voneinander entfernt sind. Konkret geht es um die Auswertung hierarchischer Datenstrukturen, d.h. wir beschftigen uns jetzt mit der Darstellung von Bumen oder sogenannten berichtet an Strukturen. Doch gehen wir das gesamte Thema wegen der zugrundeliegenden und einzigartigen Anweisung gemchlich an und beginnen damit unsere kleine Datenbank, um eine weitere Tabelle zu erweitern.
drop table organisation; / create table organisation (

288

Abfragen

unternehmen varchar2(3) not null, kst varchar2(10) not null, berichtet_an varchar2(13), constraint organisation_pk primary key (unternehmen, kst) using index tablespace indx storage (initial 10K next 10K) ) tablespace usr storage (initial 20K next 20K); / commit;
Listing 3.7: Anlage einer Tabelle zum Speichern der Organisationsstruktur

Wie anfangs gesagt finden Sie dieses Skript wieder in der Datei ABFRAGEN32.SQL. In Anlehnung zur Kostenstellentabelle speichern wir hier neben dem Unternehmen und Kostenstellenkrzel noch den Knoten, an den diese Kostenstelle berichtet, wobei die Knoten wiederum eine Kombination aus Unternehmensnummer und Kostenstellenkrzel darstellen. Betrachten wir als Nchstes die zur Zeit vorhandenen Kostenstellen, um einen berblick ber die bentigte Struktur zu erhalten.
SQLWKS> select distinct unternehmen, kst, bezeichnung 2> from kostenstelle; UNT KST BEZEICHNUNG --- ---------- -----------------------------001 EDV EDV-Betrieb 001 PERS Personalabteilung 001 PSOFT PeopleSoft-Beratung 001 SERV Softwareservice 002 MARK Marketing 002 VERT Vertrieb 6 rows selected.

Mit dieser Abfrage erhalten Sie eine Liste der realen Bltter unseres zu erstellenden Strukturbaumes. Die nchste Abbildung (vgl. Abb. 3.3) zeigt Ihnen das gewnschte Endergebnis in Form eines blichen Organigramms. Wie Sie dem Organigramm aus Abbildung 3.3 entnehmen knnen, bentigen Sie neben den sechs realen Kostenstellen auch noch drei Hilfseintrge, um die entsprechenden Hierarchieknoten darzustellen. Somit knnen Sie die Organisation mit Hilfe der im folgenden Listing dargestellten Datenstze darstellen.

Verknpfungen

289

Geschftsfhrung (GF)

Verwaltung (VERW) Personalabtlg. (PERS) Marketing (MARK) Vertrieb (VERT)


Abbildung 3.3: Organisation unseres Beispielkonzerns

Entwicklung (ENTW)

EDV-Betrieb (EDV) Softwareservice (SERV) PeopleSoft (PSOFT)

insert into insert into insert into insert into insert into insert into insert into insert into insert into commit;

organisation organisation organisation organisation organisation organisation organisation organisation organisation

values('001','GF',null); values('001','VERW','001GF'); values('001','ENTW','001GF'); values('001','PERS','001VERW'); values('002','MARK','001VERW'); values('002','VERT','001VERW'); values('001','EDV','001ENTW'); values('001','SERV','001ENTW'); values('001','PSOFT','001ENTW');

Listing 3.8: Speichern der Organisationsstruktur

Betrachten wir nun noch einmal die eingefgten Daten (vgl. Listing 3.8). Aus diesen knnen Sie beispielsweise ablesen, dass die Kostenstelle MARK aus dem Unternehmen 002 an den Knoten 001VERW berichtet. Dieser Hilfseintrag ist seinerseits wiederum mit dem Knoten 001GF also der Geschftsfhrung verknpft. Da dieser Knoten selbst nicht mehr verknpft ist, stellt er die hchste Hierarchiestufe bzw. die Wurzel der gesamten Struktur dar. Solche hierarchischen Strukturen knnen Sie natrlich auch leicht mit Hilfe herkmmlicher SQL-Sprachmittel auswerten, sofern Sie zum einen die tiefste Ebene der Struktur kennen und zum anderen alle Ebenen mit zumindest einem Element belegt sind, wobei Sie die zuletzt genannte Einschrnkung noch umgehen knnen, indem Sie die gesamte bentigte Abfrage mit Hilfe geeigneter Outer-Joins erzeugen. Da wir in unserem kleinen Beispiel wissen, dass unser Organigramm ber drei Ebenen verfgt und zum anderen alle Ebenen auch mit mindestens einem Eintrag belegt sind, knnen wir zur Auswertung der Organisationsstruktur die im Listing 3.9 gezeigte Abfrage verwenden.

290

Abfragen

SQLWKS> select '1' as "1", a.unternehmen || a.kst as lvl1, 2> '2' as "2", b.unternehmen || b.kst as lvl2, 3> '3' as "3", c.unternehmen || c.kst as lvl3 4> 5> from organisation a, 6> organisation b, 7> organisation c 8> 9> where b.berichtet_an = a.unternehmen || a.kst 10> and c.berichtet_an = b.unternehmen || b.kst; 1 1 1 1 1 1 1 6 LVL1 2 ------------- 001GF 2 001GF 2 001GF 2 001GF 2 001GF 2 001GF 2 rows selected. LVL2 ------------001ENTW 001ENTW 001ENTW 001VERW 001VERW 001VERW 3 3 3 3 3 3 3 LVL3 ------------001EDV 001SERV 001PSOFT 001PERS 002MARK 002VERT

Listing 3.9: Auswertung der Organisationsstruktur mit Hilfe einer herkmmlichen Abfrage

Wie Sie im letzten Beispiel gesehen haben, knnen beliebige berichtet-an-Strukturen durchaus mit Hilfe herkmmlicher SQL-Abfragen aufgelst werden. Das gilt vor allem auch dann, wenn dies innerhalb eines Programms passiert, so dass Sie die Mglichkeit besitzen, die bentigte Abfrage innerhalb des Programmablaufs dynamisch zu generieren, um so auf alle Eventualitten wie zum Beispiel die Anzahl der Hierarchieebenen geeignet zu reagieren. Ansonsten entspricht die bentigte Abfrage einer der Ebenenzahl entsprechenden Verknpfung der zugehrigen Tabelle, wobei die Verknpfungsverweise aus der Tabelle der Ebene n mit den entsprechenden Feldern aus der Tabelle fr die Ebene n-1 verbunden werden. In unserem Beispiel wird die Tabelle organisation in der from-Klausel aus den Zeilen fnf bis sechs der Ebenenzahl drei entsprechend oft verwendet. Dabei steht der Aliasname a fr die Ebene 1, b fr die Ebene 2 und c fr die letzte Ebene 3. Anschlieend wird in der where-Bedingung das Feld berichtet_an der Ebene 2 mit den entsprechenden Feldern aus der Ebene 1 und in gleicher Weise auch die Ebene 3 mit der Ebene 2 verknpft. Die Anweisung connect by Oracle bietet in seinem Sprachumfang eine spezielle Erweiterung, mit deren Hilfe Sie hierarchische Strukturen auch ohne die Konstruktion entsprechender Joins auswerten knnen. Konkret handelt es sich hierbei um die Anweisung connect by, mit deren Hilfe Sie die in der Tabelle gespeicherten Datenstze miteinander verketten knnen. Nach der Einfhrung dieser neuen Anweisung erweitert sich das Schema unserer select-Anweisung auf die nachfolgend aufgefhrte Struktur.

Verknpfungen

291

select <Auswahlliste> from <Tabelle> [where <Auswahlbedingungen>] [start with <Vorgabe der Wurzel>] connect by <Verkettungsbedingung> [order by <Sortierbedingungen>]

Wie Sie dem Schema entnehmen knnen, taucht zusammen mit der Anweisung connect by zustzlich noch eine neue weitere Klausel mit dem Namen start with auf, mit deren Hilfe Sie den Startpunkt fr die hierarchische Auswertung festlegen knnen. Meistens mssen Sie hier eine Auswahlbedingung spezifizieren, mit deren Hilfe die Wurzel der Struktur bestimmt werden kann. In unserem Beispiel der Organisationsstruktur konnte man die Wurzel daran erkennen, dass das Feld berichtet_an keinen Wert enthielt, d.h. in unserem Fall knnen wir den Startpunkt der Auswertung durch die nachfolgend gezeigte start-Anweisung festlegen.
start with berichtet_an is null

Bevor man jedoch die Programmierung der Verkettungsbedingungen angeht, sollte man sich darber im Klaren werden, welche Bedingungen bzw. Felder im schnen neudeutschen Sprachgebrauch die Parents bzw. Childs der Struktur kennzeichnen. Betrachten wir hierzu zunchst noch einmal den Inhalt unserer kleinen und bersichtlichen Organisationstabelle (vgl. Abb. 3.4). In dieser Abbildung habe ich die Eltern/Kind-Beziehung einmal fr ein paar ausgewhlte Beispiele mit Hilfe von Pfeilen dargestellt, wobei der Pfeil in meiner Darstellung vom Elterndatensatz auf ein zugehriges Kind zeigt. Daneben mssen Sie natrlich auch noch beachten, dass in meinem Beispiel die Verkettung beim Kind mit einem (berichtet_an) und bei den Eltern mit zwei Datenfeldern (unternehmen und kst) erfolgt.
SQLWKS> select * from organisation; UNT KST BERICHTET_AN

--- ---------- ------------001 GF 001 VERW 001 ENTW 001 PERS 002 MARK 002 VERT 001 EDV 001 SERV 001 PSOFT 001GF 001GF 001VERW 001VERW 001VERW 001ENTW 001ENTW 001ENTW

9 rows selected.

Abbildung 3.4: Darstellung der Eltern/Kind-Beziehung

292

Abfragen

Sind alle diese Dinge klar, dann steht der Kodierung der connect by-Klausel eigentlich nichts mehr im Wege. hnlich wie bei einer Verknpfungsbedingung mssen Sie die Felder des Elterndatensatzes mit den Feldern des Kinddatensatzes gleichsetzen, wobei Sie die Datenfelder aus dem Elterndatensatz mit Hilfe des Schlsselwortes prior kennzeichnen mssen.
connect by prior unternehmen || prior kst = berichtet_an

Damit haben wir alle Komponenten unserer neuen Abfrage fertiggestellt und knnen diese nun einmal ausprobieren, wobei Sie das Ergebnis dem Listing 3.10 entnehmen knnen.
SQLWKS> 2> 3> 4> select level, unternehmen, kst, berichtet_an from organisation start with berichtet_an is null connect by prior unternehmen || prior kst = berichtet_an; BERICHTET_AN ------------001GF 001VERW 001VERW 001VERW 001GF 001ENTW 001ENTW 001ENTW

LEVEL UNT KST ---------- --- ---------1 001 GF 2 001 VERW 3 001 PERS 3 002 MARK 3 002 VERT 2 001 ENTW 3 001 EDV 3 001 SERV 3 001 PSOFT 9 rows selected.

Listing 3.10: Auswertung der Organisation unter Verwendung von connect by.

Wie Sie dem Listing 3.10 entnehmen knnen, fhrt die Anwendung der connect byAnweisung zur Verwendbarkeit der Pseudospalte level. Diese Pseudospalte, die bei gewhnlichen Abfragen immer den Wert 0 enthlt, wird bei verketteten Abfragen automatisch mit der entsprechenden Ebene gefllt und kann innerhalb der Abfrage an beliebiger Stelle, beispielsweise auch als Auswahlkriterium, verwendet werden. Eine weitere Anwendung dieser Verfahrensweise ist auch die Suche nach einer Antwort auf die Frage, welche Kostenstellen alle an den Knoten 001ENTW berichten. Aufgrund unseres aktuellen Datenbestands knnte man dies natrlich auch leicht mit jeder anderen Abfragetechnik beantworten, weshalb wir unsere Organisation zunchst einmal um eine weitere Ebene erweitern.
insert into organisation values ('001','EDV1','001EDV'); insert into organisation values ('001','EDV2','001EDV'); commit;

Verknpfungen

293

Durch das Hinzufgen einer vierten Ebene ist die Beantwortung dieser Frage mit herkmmlichen Abfragetechniken nicht mehr so einfach mglich. Durch die Auflsung der Hierarchie mit Hilfe des connect by-Kommandos stellt die Beantwortung allerdings keine grere Herausforderung mehr da.
SQLWKS> 2> 3> 4> 5> 6> select level, unternehmen, kst, berichtet_an from organisation where level > 1 start with kst = 'ENTW' connect by prior unternehmen || prior kst = berichtet_an order by level; BERICHTET_AN ------------001ENTW 001ENTW 001ENTW 001EDV 001EDV

LEVEL UNT KST ---------- --- ---------2 001 EDV 2 001 SERV 2 001 PSOFT 3 001 EDV1 3 001 EDV2 5 rows selected.

Listing 3.11: Herauslsen von Teilbereichen aus der Hierarchiestruktur

Im Prinzip entspricht die Abfrage dem vorherigen Beispiel aus Listing 3.10. Zunchst einmal beginnen wir die Auflsung der Organisationsstruktur nicht an seiner Wurzel, sondern, wie Sie der Zeile 4 entnehmen knnen, mit der gesuchten Kostenstelle ENTW, d.h. unser Organisationsbaum wird durch die Abfrage erst von diesem Knoten an durchlaufen, was folglich zur Ausgabe aller an diesen Knoten berichtenden Kostenstellen fhrt. Alleine mit dieser Erweiterung wrde der Eintrag 001ENTW allerdings auch selbst ausgegeben und da dies nicht gewnscht ist, wird seine Selektion mit Hilfe der in Zeile 3 kodierten where-Bedingung ausgeschlossen. Genau wie bei allen anderen Abfragen knnen Sie zusammen mit connect by alle mglichen Datenstze von der Verarbeitung ausschlieen. Das Interessante dabei ist allerdings, dass die ausgeschlossenen Datenstze beim Durchlaufen der Hierarchie trotzdem bercksichtigt bleiben. Diesen Effekt knnen Sie mit den vorhandenen Beispieldaten leicht demonstrieren, indem Sie die where-Bedingung beispielsweise um den Ausschluss der Kostenstelle EDV erweitern. Wie Sie sich sicherlich erinnern, berichten unsere beiden zuletzt eingefgten Kostenstellen genau an diesen Knoten, d.h. man knnte zunchst vielleicht vermuten durch den Ausschluss dieses Knotens gingen auch alle daranhngenden Kinder verloren.
where level > 1 and kst <> 'EDV'

Das dem genau wie soeben beschrieben nicht so ist, zeigt die im Listing 3.12 gezeigte vollstndige Abfrage. Zwar wird die Kostenstelle EDV selbst nicht in der Ergebnismenge angezeigt, jedoch wurde sie bei der Auflsung der Hierarchie

294

Abfragen

durchaus bercksichtigt, weshalb die beiden an sie berichtenden Knoten in der Ausgabe angezeigt werden.
SQLWKS> 2> 3> 4> 5> 6> 7> select level, unternehmen, kst, berichtet_an from organisation where level > 1 and kst <> 'EDV' start with kst = 'ENTW' connect by prior unternehmen || prior kst = berichtet_an order by level; BERICHTET_AN ------------001ENTW 001ENTW 001EDV 001EDV

LEVEL UNT KST ---------- --- ---------2 001 SERV 2 001 PSOFT 3 001 EDV1 3 001 EDV2 4 rows selected.

Listing 3.12: Verwendung von where-Bedingung und connect by-Klausel

Wo viel Licht ist, da ist bekanntlich auch Schatten. Bezogen auf unsere neue connect by-Klausel zeigt sich dieser darin, dass Sie solche Abfragen nur zusammen mit einer einzigen Tabelle durchfhren knnen, d.h. die Verwendung von connect by innerhalb bzw. zusammen mit irgendwelchen Joins ist obsolet. Dies schrnkt die Verwendbarkeit dieser Anweisung zugegebenerweise auf den ersten Blick stark ein, aber wie immer muss man sich auch hier nur zu helfen wissen. Zum Beispiel knnen Sie connect by innerhalb einer Unterabfrage verwenden, um hierdurch die an einen bestimmten Knoten berichtenden Mitarbeiter zu ermitteln. In unserem Datenhaushalt finden Sie die Kostenstelle eines Mitarbeiters in seinen Gehaltsdaten und fr die Ermittlung des aktuellen Gehaltsdatensatzes mit Hilfe einer Unterabfrage haben Sie in den vorherigen Abschnitten auch schon mehrfach gesehen. Eine solche Abfrage erweitern wir nun noch um eine weitere Unterabfrage, mit deren Hilfe wir die aktuelle Kostenstelle mit den an den Knoten ENTW berichtenden Kostenstellen vergleichen.
SQLWKS> select a.persnr, a.name 2> from personalien a, 3> gehalt b 4> where b.persnr = a.persnr 5> and b.gab = (select max(gab) 6> from gehalt b1 7> where b1.persnr = b.persnr 8> and b1.lfdnr = b.lfdnr 9> and b1.gab <= sysdate 10> ) 11> and b.kst in (select kst 12> from organisation

Verknpfungen

295

13> 14> 15> 16> 17>

where level > 1 start with kst = 'ENTW' connect by prior unternehmen || prior kst = berichtet_an );

PERSNR NAME ----------- -------------------------------------------------7000003 Heiden,Magareta 7000009 Zola,Wolf 7000016 Voltair,Samuel 7000016 Voltair,Samuel 7000019 Karlo,Ellen 7000004 Hardt,Andreas 7000014 Scherer,Peter 7000020 Raymans,Heinz-Gerd 7000015 Hilsamer,Kurt 7000010 Mller,Frida 7000011 Laven,Rudolf 7000005 Nibelungen,Ellen 12 rows selected.
Listing 3.13: Verwendung von connect by in einer Unterabfrage

Eine andere Mglichkeit besteht darin, die connect by-Abfrage zusammen mit einer temporren Tabellen zu verwenden, in der zuvor alle bentigten Datenfelder kopiert werden. Die Verwendung zusammen mit einer View, in der die beteiligten Tabellen zuvor verknpft werden ist leider nicht mglich, denn die connect byAnweisung funktioniert nur, wenn die View nicht ausgefhrt werden muss, so dass bei Ausfhrung des in der View gespeicherten SQL-Statements der connect by-Befehl doch wieder zusammen mit mehren Tabellen angewendet wird, was jedoch wie eben beschrieben nicht mglich ist. Die Verwendung des Befehls zusammen mit einer temporren Tabelle mchte ich Ihnen kurz an einem einfachen Beispiel demonstrieren. Konkret soll eine Abfrage erstellt werden, mit deren Hilfe die einzelnen Mitarbeiter entlang der aktuellen Organisationsstruktur ausgegeben werden knnen. Hierzu erstellen wir uns zunchst einmal die View aktuelles_gehalt, mit deren Hilfe die Namen der Mitarbeiter und deren aktuelle Kostenstelle und bei Bedarf weitere Daten aus der Gehaltshistorie bereitgestellt wird.
create or replace view aktuelles_gehalt as select a.persnr, b.lfdnr, a.name, b.kst from personalien a, gehalt b where b.persnr = a.persnr and b.gab = (select max(gab) from gehalt b1 where b1.persnr = b.persnr

296

Abfragen

and b1.lfdnr = b.lfdnr and b1.gab <= sysdate ); commit;


Listing 3.14: Erzeugen der View aktuelles_gehalt zur Ermittlung der aktuellen Kostenstelle

Anschlieend schicken wir anstelle einer einzelnen Abfrage ein kleines Skript auf die Reise, in dem wir zunchst unsere temporre Tabelle erstellen und mit Daten fllen und diese anschlieend in der gewnschten Weise auswerten.
drop table tmp_aktuelle_orga; create table tmp_aktuelle_orga as select b.*, a.persnr, a.lfdnr, a.name from aktuelles_gehalt a, organisation b where b.kst = a.kst (+); commit; select level, unternehmen, kst, berichtet_an, persnr, lfdnr, name from tmp_aktuelle_orga start with berichtet_an is null connect by prior unternehmen || prior kst = berichtet_an; drop table tmp_aktuelle_orga;
Listing 3.15: Erzeugen der Organisationsauswertung mit Hilfe eines Skriptes

Eine solche Verfahrensweise, eine undurchfhrbare oder bermig komplexe Abfrage mit Hilfe eines Skriptes in einzelne Teilschritte zu zerlegen, wobei am Ende eine zuvor erstellte einfache Ergebnistabelle ausgewertet wird, stellt unter Umstnden nicht nur hier eine interessante Alternative dar. Zum einen werden hierdurch bestimmte Auswertungen berhaupt erst mglich und zum anderen gibt es Abfragen, die zerteilt in mehrere Einzelschritte insgesamt schneller laufen, als wenn sie als Superabfrage gestartet werden. In unserem Beispiel lschen wir als Erstes die Tabelle tmp_aktuelle_orga, was innerhalb unseres Skriptes blicherweise zu einer Hinweismeldung fhrt, da die Tabelle im Normalfall nicht vorhanden sein sollte. Anschlieend wird die eben gelschte Tabelle erstellt, wobei die neue Tabelle mit Hilfe der besonderen create table as select-Befehlsvariante, also durch Kopieren von Daten erzeugt wird. In dem hierbei verwendeten select-Befehl verknpften wir die soeben erstellt View aktuelles_gehalt mit der Organisationstabelle, wobei die von der View gelieferten Mitarbeiterdaten per Outer-Join verknpft werden, so dass die gesamte Organisationsstruktur mit allen unbesetzten Knoten oder Kostenstellen erhalten bleibt.

Verknpfungen

297

select b.*, a.persnr, a.lfdnr, a.name from aktuelles_gehalt a, organisation b where b.kst = a.kst (+);

Im nchsten Schritt unseres Skripts wird die erstellte Hilfstabelle unter Anwendung des connect by-Befehls ausgewertet. Dabei entspricht die Vorgehensweise eigentlich genau der Auswertung der einfachen Organisationstabelle.
select level, unternehmen, kst, berichtet_an, persnr, lfdnr, name from tmp_aktuelle_orga start with berichtet_an is null connect by prior unternehmen || prior kst = berichtet_an;

Durch diese Abfrage werden die gewnschten Daten am Bildschirm angezeigt bzw. aus der Datenbank abgerufen und im Anschluss daran wird die temporre Tabelle am Ende unseres Skripts wieder gelscht.
LVL ------1 2 3 4 4 3 4 4 3 4 4 3 4 4 3 4 4 3 3 3 3 ... 2 3 3 ... 3 48 rows UNT --001 001 001 001 001 001 001 001 001 001 001 001 001 001 001 001 001 001 001 001 001 KST -------GF ENTW EDV EDV1 EDV2 EDV EDV1 EDV2 EDV EDV1 EDV2 EDV EDV1 EDV2 EDV EDV1 EDV2 PSOFT PSOFT PSOFT PSOFT BERICHTET_AN PERSNR LFDNR NAME ------------- --------- ------- ----------------001GF 001ENTW 001EDV 001EDV 001ENTW 001EDV 001EDV 001ENTW 001EDV 001EDV 001ENTW 001EDV 001EDV 001ENTW 001EDV 001EDV 001ENTW 001ENTW 001ENTW 001ENTW 001GF 001VERW 001VERW 001VERW

7000003

0 Heiden,Magareta

7000009

0 Zola,Wolf

7000016

0 Voltair,Samuel

7000019

0 Karlo,Ellen

7000016

2 Voltair,Samuel

7000004 7000005 7000015 7000020

0 0 0 0

Hardt,Andreas Nibelungen,Ellen Hilsamer,Kurt Raymans,Heinz-Gerd

001 VERW 002 MARK 002 MARK 002 VERT selected.

7000006 7000022 7000017

0 Beckmann,Yonne 0 Keun,Monika 1 Hoerbinger,Julia

Listing 3.16: Ergebnis der mit Listing 3.15 erstellten Auswertung

298

Abfragen

3.3

nderungsabfragen

Nachdem wir nun in den vorherigen Abschnitten die verschiedenen Auswahlabfragen behandelt haben, beschftigen wir uns im Folgenden nun mit der zweiten Abfragekategorie, den sogenannten nderungsabfragen. Wie der Name schon sagt, dienen die zu diesen Abfragen gehrenden SQL-Anweisungen dazu, die in den Tabellen gespeicherten Daten zu verndern. Hierbei kann man grundstzlich wieder zwischen einfachen nderungsabfragen und selbsterstellten nderungscursorn unterscheiden. Im ersten Fall erfolgt die nderung der Tabelle mit Hilfe eines speziellen SQL-Kommandos, wobei hierbei im Unterschied zu manch anderen Datenbanksystemen immer nur eine einzelne Tabelle verarbeitet wird. Der zweite Fall fhrt zur Verwendung von PL/SQL-Sprachelementen und ermglicht Ihnen damit eigentlich so ziemlich alles was denkbar ist. Im Rahmen solcher Cursor knnen nicht nur mehrere Tabellen verarbeitet werden, sondern es sind ebenfalls unterschiedliche Transaktionen denkbar (Lschen der einen und ndern der anderen Tabelle).

3.3.1

ndern von Daten

Zum ndern von Daten finden Sie im SQL-Sprachumfang blicherweise den Befehl update, mit dessen Hilfe eine oder mehrere Spalten einer Tabelle gendert werden knnen. Im Unterschied zu manch anderem Datenbanksystem kennt der updateBefehl in Oracle allerdings keine from-Klausel, weshalb mit ihm immer nur eine Tabelle gendert bzw. verarbeitet werden kann. Insgesamt besitzt die update-Anweisung die nachfolgend aufgefhrte Struktur.
update <Tabelle> set <nderungsanweisungen> where <Auswahlbedingungen>

Zunchst mssen Sie hinter dem Schlsselwort update die zu ndernde Tabelle spezifizieren. Als Zweites mssen Sie dahinter mit Hilfe der set-Anweisung die bzw. alle zu ndernden Spalten vorgeben. Dabei werden mehrere Spalten durch Komma getrennt und jede einzelne Spalte wird in der Form
<Spaltenname> = <Neuer Wert>

gendert. Die Berechnung des neuen Wertes knnen Sie mit Hilfe eines Ausdrucks erstellen, bei dem Sie neben Konstanten und Funktionen auch Bezug auf alle Spalten der Tabelle nehmen knnen. Zum Schluss knnen Sie mit Hilfe der whereBedingung die zu ndernden Datenstze durch Vorgabe gewhnlicher Auswahlbedingungen einschrnken. Im Listing 3.17 finden Sie zwei einfache Beispiele fr die Verwendung der update-Anweisung. Aufgrund einer nderungen der fr das Geschlecht verwendeten Schlssel mssen alle in der Datenbank vorhandenen Werte gendert werden. Mnnliche Mitarbeiter sollen zuknftig mit einer 1 und die weiblichen Kollegen mit einer 2 gekennzeichnet werden.

nderungsabfragen

299

update personalien set geschlecht = '1' where geschlecht = 'M'; update personalien set geschlecht = '2' where geschlecht = 'W';
Listing 3.17: Verwenden einfacher update-Anweisungen

Verwenden von Unterabfragen Durch die Verwendung von Unterabfragen knnen Sie im Rahmen der updateAnweisung doch mehr als eine Tabelle verwenden, was sowohl fr die where-Bedingung als auch fr die Erstellung des nderungsausdrucks gilt. Bei der Programmierung der set-nderungsanweisung mssen Sie sich allerdings entscheiden, ob Sie einen Ausdruck oder eine Unterabfrage verwenden, d.h. das Vermischen dieser beiden Konstruktionen in der Form
set zulage = zulage + (select ....)

ist nicht mglich. Wie Sie gleich sehen werden, besteht allerdings die Mglichkeit, die Felder der zu ndernden Tabelle innerhalb der Unterabfrage zu verwenden, so dass die eben genannte Konstruktion folgendermaen umformuliert werden knnte.
set zulage = (select zulage + ....)

Im Folgenden sollen unsere Gehaltsdaten gendert werden. Konkret soll die Zulage des aktuellsten Gehaltsdatensatzes mit einem zwlftel der Lohnsumme der Lohnart 350 aus dem Jahr 1999 erhht werden.
update gehalt a set a.zulage = (select a.zulage + nvl(sum(betr01+ betr02+ betr03+ betr04+ betr05+ betr06+ betr07+ betr08+ betr09+ betr10+ betr11+ betr12 ), 0 ) / 12 from lohnarten b where b.persnr = a.persnr and b.lfdnr = a.lfdnr and to_char(b.gab,'YYYY')='1999'

300

Abfragen

and b.la = '350' and b.satzart = 'DM' ) where a.gab = (select max(gab) from gehalt a1 where a1.persnr = a.persnr and a1.lfdnr = a.lfdnr );
Listing 3.18: Erstellen einer udpate-Anweisung unter Verwendung von Unterabfragen

Wie Sie dem Beispiel (vgl. Listing 3.18) entnehmen knnen, enthlt sowohl die set, als auch die where-Klausel eine Unterabfrage zur Berechnung der neuen Werte bzw. zur Einschrnkung der zu ndernden Datenstze. Beginnen wir bei der Beschreibung mit where-Bedingung, in der wir die schon mehrfach bekannte max-Unterabfrage zur Ermittlung des aktuellen Gehaltsdatensatzes verwenden. Da wir diesmal allerdings keine Einschrnkung auf das gab-Datenfeld vornehmen, liefert die Unterabfrage in der Tat das Datum der letzten vorhandenen Gehaltssituation. Neben solchen Unterabfragen findet man zusammen mit update-Befehlen hufig auch Unterabfragen vom Typ exists bzw. not exists, so dass nur Datenstze gendert werden, wenn die in der Unterabfrage gesuchten Datenstze vorhanden bzw. eben nicht vorhanden sind. Auerdem mchte ich an dieser Stelle schon einmal vorwegnehmend bemerken, dass ich schon hufiger update-Anweisungen, bei denen im Auswahlbereich eine oder mehrere Unterabfragen verwendet wurden, durch einen entsprechenden nderungscursor ausgetauscht habe, wodurch die gesamte nderungstransaktion von der Datenbank schneller abgearbeitet wurde. Das liegt vor allem daran, dass Sie die Unterabfrage beim Cursor in eine gewhnliche Verknpfung berfhren knnen, so dass die bentigten Datenstze eben in einigen Fllen schneller als mit der entsprechenden Unterabfrage geliefert werden. Die Berechnung der neuen Zulage erfolgt ebenfalls mit Hilfe einer Unterabfrage auf unsere Abrechnungsergebnisse, die in der Tabelle lohnarten gespeichert sind. Dort suchen wir fr die aktuelle Personalnummer die fr die vorgegebenen Eckdaten (Lohnart, Jahr, Satzart) passenden Datenstze und ermitteln hierfr die Summe der vorhandenen Betragsfelder. Sind fr eine Personalnummer gar keine Datenstze vorhanden, dann wrde die verwendete sum-Funktion in dem Fall den Wert null zurckliefern, weshalb wir diese Flle mit Hilfe der nvl-Funktion in eine regulre 0 umwandeln. Diese Summe teilen wir anschlieend durch zwlf und addieren auf diesen Quotienten den alten Zulagenbetrag, um damit den gewnschten neuen Betrag zu erhalten. Wie Sie dem Beispiel weiterhin entnehmen knnen, habe ich der zu ndernden Tabelle genau wie bei den Auswahlabfragen einen Aliasnamen gegeben, um die Verwendung der Felder innerhalb der Unterabfragen zu vereinfachen.

nderungsabfragen

301

3.3.2

Lschen von Daten

Diesen Buchabschnitt htte ich eigentlich recht schnell erstellen knnen, in dem ich zunchst den vorherigen Abschnitt kopiere und anschlieend die Wrter nderung durch Lschen und update durch delete ersetze. Aber da es Gott sei Dank doch ein paar kleine Unterschiede gibt, will ich es mir dann doch nicht ganz so einfach machen. Entsprechend dem SQL-Standard wird eine Lschanweisung durch das Schlsselwort delete eingeleitet. Im Unterschied zu einigen anderen Datenbanksystemen und in Analogie zu den nderungsabfragen kennt Oracle auch hierbei wieder keine from-Klausel, so dass die Lschabfrage prinzipiell dem folgendem Schema entspricht.
delete <Tabelle> where <Auswahlbedingungen>

Dabei folgt hinter dem Schlsselwort delete der Name der Tabelle aus der die Datenstze gelscht werden sollen und die where-Klausel fhrt in Form gewhnlicher Auswahlbedingungen zur Auswahl der zu lschenden Datenstze. Das nchste Beispiel (vgl. Listing 3.19) zeigt hierfr ein Anwendungsbeispiel, indem mit Hilfe einer Lschabfrage alle Personalien gelscht werden, deren Geschlecht nicht in einer Liste bestimmter Vergleichswerte enthalten ist.
delete personalien where geschlecht not in ('M','W','1','2');
Listing 3.19: Verwenden einer einfachen Lschabfrage

Genau wie bei den nderungsabfragen knnen Sie innerhalb der where-Bedingung wieder Ausdrcke mit Konstanten, Funktionen und allen in der Tabelle vorhandenen Feldern erstellen. Verwenden von Unterabfragen Auch beim Lschen besteht natrlich wieder die Mglichkeit, innerhalb der whereKlausel Unterabfragen zu verwenden, um das Lschen der Datenstze von Konstellationen innerhalb anderer Tabellen abhngig zu machen. Bleiben wir hierbei auch gleich bei unserem letzten Beispiel, dem Lschen spezieller Datenstze aus der Personalientabelle. Aufgrund unserer Datenstruktur mssen beim Lschen von Personalstammdaten eigentlich auch immer die eventuell zugehrigen Datenstze der anderen Tabellen gelscht werden. Zwar sollte die Datenbank dies automatisch durchfhren, und wir werden zu spterer Stunde auch noch an diesem Dilemma arbeiten, doch zur Zeit mssen wir noch selbst fr die Konsistenz unserer Datenbank sorgen. Damit heit unsere Aufgabenstellung beispielsweise zunchst alle Gehaltsdatenstze zu lschen, die mit fehlerhaften Personalstammstzen verknpft sind, bevor dann in einem zweiten Schritt genau diese fehlerhaften Personalien gelscht werden.

302

Abfragen

delete gehalt a where exists(select 1 from personalien b where b.persnr = a.persnr and geschlecht not in ('M','W','1','2') );
Listing 3.20: Anwenden der delete-Anweisung zusammen mit einer exists-Unterabfrage

Mit Hilfe einer exists-Unterabfrage berprfen wir fr jeden Gehaltsdatensatz, ob der zugehrige Personalstammdatensatz fehlerhaft ist, was in dem Fall zum Lschen des aktuellen Gehaltsdatensatzes fhrt. Sind die Personalstammdatenstze allerdings schon weg, dann knnen Sie den Lschvorgang der Gehaltsdaten natrlich auch von der Nichtexistenz der zugehrigen Personalien abhngig machen, wofr Sie im Listing 3.21 ein Beispiel finden.
delete gehalt a where not exists(select 1 from personalien b where b.persnr = a.persnr );
Listing 3.21: Lschen von Datenstzen mit Hilfe einer not exists-Unterabfrage

Bei dieser Variante prfen wir fr jeden Datensatz der Gehaltstabelle, ob ein zugehriger Personalstammdatensatz existiert. Falls nicht, liegt eine fehlerhafte Datenkonstellation vor, weshalb wir den Gehaltsdatensatz in dem Fall lschen. Tabelle abschneiden Sofern Sie alle Datenstze einer Tabelle lschen wollen, knnen Sie das natrlich dadurch realisieren, indem Sie einfach keine where-Bedingung spezifizieren. So lscht die Anweisung
delete gehalt;

alle vorhandenen Gehaltsdatenstze. Bei groen Tabellen mit vielleicht mehreren Millionen Datenstzen drfte dieser Vorgang allerdings einen Moment dauern, da die Lschung jedes einzelnen Datensatzes im Rollback-Segment protokolliert wird, damit die gesamte Transaktion am Ende vielleicht doch noch zurckgerollt werden kann. Meistens ist das Lschen einer ganzen Tabelle aber ein Vorgang ohne wenn und aber, weshalb es hierfr in Oracle wie auch in vielen anderen Datenbanksystemen einen speziellen Befehl gibt.
truncate table gehalt;

Mit der Anweisung truncate table lschen Sie die gesamte vorgegebene Tabelle. Beachten Sie hierbei allerdings, dass es nach dem Absenden dieser Anweisung kein Zurck mehr gibt, d.h. Sie mssen die Transaktion nicht durch einen commit-

nderungsabfragen

303

Befehl abschlieen, knnen sie im Gegenzug allerdings auch nicht durch ein rollback-Kommando rckgngig machen. Die Ausfhrung der truncate table-Anweisung fhrt intern zu einer Art Abschneiden des gesamten Tabelleninhalts, d.h. im Unterschied zur delete-Anweisung wird die Tabelle nicht Satz fr Satz gelscht, sondern dies passiert in einem Rutsch, weshalb der Befehl auch bei Tabellen mit vielen Millionen Datenstzen sofort fertig wird.

3.3.3

Einfgen von Daten

Die Letzte der einfachen nderungsanweisungen dient dem Einfgen neuer Datenstze in eine Tabelle und heit insert into. In manchen Datenbanksystemen fllt die Verwendung des zweiten Wrtchens into in die Kategorie Geschmacksache; in Oracle ist die gemeinsame Verwendung der beiden Schlsselwrter jedoch zwingend. Bei der Anwendung der insert into-Anweisung existieren im Wesentlichen zwei unterschiedliche Varianten. Bei der einen Variante wird lediglich ein einzelner Datensatz in die Tabelle eingefgt, wobei hierbei die einzelnen Werte der verschiedenen Spalten vorgegeben werden. Im anderen Fall erfolgt das Einfgen der neuen Daten mit Hilfe einer Abfrage, so dass auf diese Weise beliebig viele Datenstze auf einmal in die Tabelle angefgt werden knnen. Auerdem knnen Sie eine Einfgeoperation mit oder ohne Aufzhlung der einzelnen Feldnamen durchfhren, wobei letzteres nur dann funktioniert, wenn Sie zum einen die zugehrigen Werte genau in der aus der Tabellendefinition resultierenden Reihenfolge liefern und zum anderen damit naheliegender weise alle Datenfelder der Zieltabelle spezifizieren. Einzelne Datenstze einfgen Die Kodierung einer Einfgeoperation fr einen einzelnen neuen Datensatz entspricht im Prinzip der nachfolgend aufgefhrten Struktur:
insert into <Tabelle> [Feldliste] values <Werteliste>

Hinter den Schlsselwrtern insert into folgt der Tabellennamen, in der die Einfgeoperation durchgefhrt werden soll. Anschlieend knnen Sie in Klammern eine Liste von Feldnamen vorgeben, fr die bzw. in deren Reihenfolge die einzufgenden Spaltenwerte geliefert werden. Diese mssen Sie nach dem Schlsselwort values ebenfalls in Klammern spezifizieren.
insert into gehalt (persnr, lfdnr, gab, kst, gehalt, zulage) values ('7000010', 1, to_date('2000-01-01','YYYY-MM-DD'), 'MARK', 7800, 100);
Listing 3.22: Durchfhren einer Einfgeoperation mit Hilfe einzelner Datenwerte

In unserem Beispiel (vgl. Listing 3.22) fgen wir mit Hilfe der insert into-Anweisung einen neuen Gehaltsdatensatz in die Datenbank ein. Wie Sie dem Listing entnehmen knnen, habe ich dabei hinter dem Tabellennamen alle vorhandenen Felder

304

Abfragen

in Klammern aufgezhlt. Die dabei verwendete Reihenfolge ist gleichgltig, denn wichtig ist nur, dass die Reihenfolge der mit der values-Klausel gelieferten Werte zu dieser Feldnamensliste passt. Das Einzige, was Oracle in dem Zusammenhang berprft, ist, ob die Datentypen entsprechender Feldnamen und Werte zueinander passen. Eigentlich sollten Sie eine solche Einfgeoperation immer genau in der eben beschriebenen Form benutzen, auch wenn Sie diese in besonderen Situationen etwas verkrzen knnen. Das ist der Fall, wenn Sie zum einen die genaue Reihenfolge der in der Tabelle gespeicherten Felder kennen und zum anderen in der values-Klausel fr jedes Feld einen Wert in genau dieser Reihenfolge liefern. Im Zweifel knnen Sie die bentigte Feldreihenfolge mit Hilfe der desc-Anweisung ermitteln.
SQLWKS> desc gehalt Column Name -----------------------------PERSNR LFDNR GAB KST GEHALT ZULAGE Null? -------NOT NULL NOT NULL NOT NULL NOT NULL NOT NULL NOT NULL Type ---VARCHAR2(11) NUMBER(38) DATE VARCHAR2(10) NUMBER(9,2) NUMBER(9,2)

Listing 3.23: Ermittlung der Struktur der Gehaltstabelle mit Hilfe der desc-Anweisung

Wenn Sie nun die einzelnen Werte genau in dieser Reihenfolge liefern, dann knnten Sie die insert into-Anweisung auch folgendermaen verwenden:
insert into gehalt values ('7000010', 1, to_date('2000-01-01','YYYY-MM-DD'), 'MARK', 7800, 100);

Ich persnlich halte davon wie ich zugeben muss, von besonderen Ausnahmefllen vielleicht einmal abgesehen, nicht so besonders viel, denn ich finde diese Form schwieriger nachzuvollziehen und fehleranflliger. Auch wenn das vielleicht mal wieder Ansichtssache ist, so mssen Sie in jedem Fall zugeben, dass man hierbei die Struktur der Einfgetabelle im Kopf haben muss, um die Einfgeoperation verstehen zu knnen. Ich persnlich habe eigentlich so einiges im Kopf, wobei sich die Strukturen aller mglichen Eingefgetabellen nur selten darunter befinden. Einfgen mit Hilfe einer Abfrage Die andere Variante der Einfgeanweisung besteht darin, die Werte der neuen Datenstze mit Hilfe einer Abfrage zu ermitteln, was zu folgender nderung unseres Befehlsschemas fhrt.
insert into <Tabelle> [Feldliste] select <Auswahlabfrage>

nderungsabfragen

305

Das Einzige was Sie hierbei beachten mssen, obwohl auch das eigentlich auf der Hand liegt, ist, dass Sie innerhalb der select-Klausel der Auswahlabfrage alle fr die Zieltabelle bentigten Spalten bereitstellen mssen. Ansonsten knnen Sie in dieser Abfrage alle bisher kennen gelernten Konstrukte bzw. Techniken verwenden. Im Folgenden wollen wir uns diese Variante der insert into-Anweisung wieder an einem geeigneten Beispiel anschauen. In unserer Datenbank sollen alle aktiven bzw. mit keinem Austrittsdatum versehenen Mitarbeiter zum 01.01.2001 eine Gehaltserhhung von fnf Prozent erhalten. Ein weiteres Kriterium fr die automatische Erstellung dieses neuen Gehaltsdatensatzes ist allerdings auch, dass fr den 01.01.2001 bzw. fr sptere Termine noch keine Gehaltssituationen vorhanden sind. Bei solchen Aufgabenstellungen ist es nicht schlecht, im ersten Schritt zunchst einmal die bentigte Auswahlabfrage zu erstellen bzw. zu testen, bevor Sie diese im Rahmen der Einfgeoperation verwenden.
SQLWKS> select a.persnr, a.lfdnr, to_date('2001-01-01','YYYY-MM-DD'), a.kst, a.gehalt * 1.05, a.zulage 2> from gehalt a, bvs b 3> where a.gab = (select max(gab) 4> from gehalt a1 5> where a1.persnr = a.persnr 6> and a1.lfdnr = a.lfdnr 7> ) 8> and a.gab < to_date('2001-01-01','YYYY-MM-DD') 9> and b.persnr = a.persnr 10> and b.lfdnr = a.lfdnr 11> and b.austrt is null 12> PERSNR LFDNR TO_DATE('2001-01-01' KST A.GEHALT*1 ZULAGE ----------- ---------- -------------------- -------- ---------- ------7000003 0 01-JAN-01 EDV 6825 0 7000004 0 01-JAN-01 PSOFT 8242.5 512 7000005 0 01-JAN-01 PSOFT 6825 220 7000006 0 01-JAN-01 MARK 6193.95 100 7000007 0 01-JAN-01 PERS 6825 200 7000009 0 01-JAN-01 EDV 6510 55.9 7000011 0 01-JAN-01 PSOFT 7560 0 7000012 0 01-JAN-01 PERS 5378.1 12 ... 17 rows selected.

Mit dieser Abfrage ermitteln wir fr alle aktiven Mitarbeiter das neue Grundgehalt zum konstanten Datum 01.01.2001. Hierzu verknpfen wir die Gehaltsdaten mit den Beschftigungsdaten (Zeile 9 und 10) und legen mit Hilfe der Zeile 11 zustzlich fest, dass das dort vorhandene Austrittsdatum leer sein muss.

306

Abfragen

Mit Hilfe der Unterabfrage der Zeilen drei bis sieben selektieren wir pro Mitarbeiter die jeweils aktuellste Gehaltshistorie. Ist deren Gltigkeitsdatum kleiner dem 01.01.2001 (siehe Zeile 8), dann existieren fr den Mitarbeiter keine Zukunftsdaten und zum 01.01.2001 ist ebenfalls noch keine Gehaltshistorie vorhanden. Die hierdurch ausgewiesene Gehaltssituation entspricht also genau dem letzten Stand, mit Ausnahme des von uns konstant vorgegebenen Gltigkeitsdatums und dem neu berechneten Grundgehalt. Sofern Sie nun mit dem Ergebnis der Abfrage zufrieden sind, ich bin es, dann knnen Sie als Nchstes zur Erweiterung der eigentlich bentigten Einfgeanweisung bergehen.
insert into gehalt (persnr, lfdnr, gab, kst, gehalt, zulage) select a.persnr, a.lfdnr, to_date('2001-01-01','YYYY-MM-DD'), a.kst, a.gehalt * 1.05, a.zulage from gehalt a, bvs b where a.gab = (select max(gab) from gehalt a1 where a1.persnr = a.persnr and a1.lfdnr = a.lfdnr ) and a.gab < to_date('2001-01-01','YYYY-MM-DD') and b.persnr = a.persnr and b.lfdnr = a.lfdnr and b.austrt is null;
Listing 3.24: Verwenden von insert into zusammen mit einer Auswahlabfrage

Wie Sie dem Listing 3.24 entnehmen knnen, ist es von einer fertigen Auswahlabfrage zu einer Einfgeabfrage wahrlich kein weiter Weg. Eigentlich mssen Sie nur die Schlsselwrter insert into darber bzw. davor schreiben, den Namen der einzufgenden Tabellen vorgeben und anschlieend die zur Auswahl passenden Spaltennamen auflisten.

3.3.4

Sperren von Datenstzen

Technisch sorgt das Datenbanksystem ganz alleine dafr, dass die Konsistenz der Datenbank trotz konkurrierender nderungsabfragen im Mehrbenutzerbetrieb erhalten bleibt. Hierzu werden vom Datenbanksystem auch Sperrungen von Datenstzen vorgenommen, so dass andere Transaktionen unter Umstnden warten mssen, bis die Sperrungen mit dem Beenden der zugehrigen nderungsoperation aufgehoben werden. Manchmal ist das allerdings zu wenig und meistens aus ablauftechnischen Grnden mchte man nderungen durch Dritte vermeiden, solange die eigene nderungsabfrage in der Datenbank aktiv ist. Aus diesem Grund existiert die for update-Klausel, mit deren Hilfe Sie die gelesenen Daten vor nderungen und Sperrversuchen andere Anwender schtzen knnen. Dieser Schutz bleibt so lange erhalten, bis Sie die Transaktion mittels commitAnweisung abschlieend oder durch ein rollback abbrechen bzw. zurckrollen.

nderungsabfragen

307

Sie knnen die Verfahrensweise auch im Einbenutzerbetrieb gut ausprobieren bzw. simulieren, indem Sie einfach einmal Ihren SQL-Editor zweimal starten. Geben Sie anschlieend im ersten Arbeitsfenster folgende Abfrage ein, um die Personalstammdaten fr die selektierten Datenstze zu sperren.
select * from personalien where persnr = '7000188' for update

Versuchen Sie nun im gleichen Arbeitsfenster den gelesenen und gesperrten Datensatz zu ndern, indem Sie beispielsweise folgende nderungsabfrage verwenden.
update personalien set geschlecht = 'W' where persnr = '7000188';

Wie nicht anders zu erwarten war, knnen Sie die gewnschte nderungsoperation in der gleichen Sitzung ohne Probleme durchfhren. Schlielich haben Sie die Sperrung ja auch fr Ihren Gebrauch durchgefhrt, d.h. Sie wollten anderen aber nicht sich selbst von der Bearbeitung ausschlieen. Also gehen wir zum nchsten Schritt ber und geben die gleiche nderungsabfrage in der zweiten Programminstanz unseres SQL-Editors ein, wobei dieses Programm nach dem Absenden des Befehls hngt, weil die zweite nderungsabfrage auf die Freigabe des gesperrten Datensatzes durch die erste Programminstanz wartet. Wenn Sie nun im ersten Arbeitsfenster die Befehle commit oder rollback zum Abschlieen oder Zurckrollen Ihrer Transaktion eingeben, dann wird anschlieend auch die nderungsabfrage des zweiten Fensters sofort ausgefhrt. Das Ganze funktioniert natrlich genauso, wenn Sie im zweiten Arbeitsfenster statt der nderungsabfrage versuchen, den entsprechenden Datensatz ebenfalls zu sperren, d.h. Sie verwenden hier noch einmal die gleiche Selektionsabfrage mit der for updateKlausel. Wenn Sie nicht wollen, dass der Sperrversuch Ihre Abfrage fr immer bzw. bis zum Auftreten eines eventuellen Timeouts hngen lsst, dann sollten Sie zustzlich die nowait-Klausel verwenden, die dazu fhrt, dass Ihre Abfrage sofort mit einer entsprechenden Fehlermeldung beendet wird, sofern die zu sperrenden Objekte bzw. Datenstze aufgrund konkurrierender Zugriffe nicht verfgbar sind.
select * from personalien where persnr = '7000188' for update nowait;

Verwenden mehrerer Tabellen Sind mehrere Tabellen an der Abfrage beteiligt, dann sperrt die for update-Klausel automatisch die selektierten Datenstze aus allen in der Abfrage verwendeten Tabellen. Die im folgenden Beispiel verwendete Abfrage sperrt also nicht nur den Personalstammdatensatz mit der Personalnummer 7000188, sondern ebenfalls das Land mit dem Schlssel DEU.

308

Abfragen

select a.persnr, a.name, a.land, b.bezeichnung from personalien a, laender b where b.land = a.land and a.persnr = '7000188' for update;

Ist dieser Effekt unerwnscht, dann knnen Sie die for update-Klausel erweitern und hierdurch die zu sperrenden Tabellen gezielt festlegen, indem Sie hinter dieser Klausel fr jede zu sperrende Tabelle ein reprsentatives Feld aufzhlen. Wie gesagt folgt diese Feldliste hinter der for update-Klausel und wird durch das Schlsselwort of eingeleitet.
select a.persnr, a.name, a.land, b.bezeichnung from personalien a, laender b where b.land = a.land and a.persnr = '7000188' for update of a.geschlecht, b.land;

Das letzte Beispiel bewirkt natrlich dasselbe, als wenn Sie die zustzliche ofOption weggelassen htten, denn konkret haben wir aus jeder beteiligten Tabelle ein Feld aufgezhlt, so dass auch wieder die selektierten Datenstze jeder Tabelle gesperrt werden. Welches Feld Sie hierbei aus den Tabellen verwenden, ist in der Tat vllig egal, denn das Feld dient nur als Verweis auf die zugrundeliegende Tabelle. Sollen in unserem Beispiel jetzt aber wirklich nur die selektierten Personalstammdaten gesperrt werden, dann mssen Sie die Abfrage bzw. die for update ofKlausel folgendermaen abndern.
select a.persnr, a.name, a.land, b.bezeichnung from personalien a, laender b where b.land = a.land and a.persnr = '7000188' for update of a.geschlecht;

Sperren ganzer Tabellen Manchmal ist es ntzlich, und das gilt vor allem oft fr Batch-Hintergrundprozesse, alleiniger Herrscher ber einen Datenbestand zu sein. Aus dem Grund besteht neben dem Sperren von selektierten Datenstzen auch noch die Mglichkeit, gleich ganze Tabellen gegen nderungen durch Dritte zu schtzen. Das nachfolgende Beispiel sperrt beispielsweise die komplette Lndertabelle vor dem ndern bzw. Sperren von Datenstzen durch Dritte.
lock table laender in share row exclusive mode;

Der hierzu notwendige Befehl heit lock table, dem die zu sperrende Tabelle folgt. Dahinter mssen Sie das Schlsselwort in verwenden, dem die Art der durchzufhrenden Sperrung folgt. Abgeschlossen wird der Befehl durch das Schlsselwort mode. Die hier verwendete Sperrmethode share row exclusive fhrt wie schon gesagt zur Sperrung aller in der Tabelle vorhandenen Datenstze. hnliches htten Sie auch mit der Methode exclusive erreichen knnen, wobei Sie eine vollstndige bersicht aller verfgbaren Methoden in der Oracle-Dokumentation im Buch Oracle8 SQL-Reference finden.

nderungsabfragen

309

In jedem Fall gilt eine durchgefhrte Sperrung so lange, bis Sie die Transaktion mit einem commit-Befehl beenden oder mittels rollback zurckrollen.

3.3.5

Erstellen eines nderungscursors

Wie Sie mit Hilfe der letzten Abschnitte hoffentlich gesehen haben, ist die Verwendung der nderungsabfragen bzw. der zugehrigen SQL-Anweisungen eigentlich recht einfach. Die zugrundeliegenden Anweisungen sind ziemlich kompakt, und wenn an einer nderungsabfrage berhaupt etwas schwierig sein kann, dann ist das eine verwendete komplexe where-Bedingung. Allerdings knnen Sie mit den bisher kennen gelernten nderungsabfragen immer nur eine Tabelle gleichzeitig ndern und manchmal zwingt einen die fehlende from-Klausel und der damit verbundene Verwendungszwang von Unterabfragen zu ineffizienten Auswahlkonstruktionen. Worum handelt es sich nun bei den jetzt beschriebenen Cursorn? Zunchst einmal handelt es sich hierbei um eine Konstruktion, die zumindest intern von Oracle bei allen bisher verwendeten Abfragetypen angewendet wird. Generell knnen Sie sich einen Cursor als einen Speicherbereich vorstellen, in dem die Ergebniszeilen einer Abfrage gepuffert werden, wobei zustzliche Methoden bereitgestellt werden, die einzelnen Ergebniszeilen abzurufen. Bei jeder bisher erstellten Abfrage hat Oracle also zunchst einmal einen solchen Cursor implizit erstellt und die Daten mit seiner Hilfe bereitgestellt bzw. gendert. Worum es jetzt geht ist zum einen diesen Cursor explizit, als selbst, zu erstellen und das abrufen der einzelnen Ergebniszeilen selbst in die Hand zu nehmen, wozu Sie im PL/SQL-Sprachumfang die bentigten Hilfsmittel finden. Wie funktioniert nun aber die explizite Verwendung eines Cursors? Ich finde, man kann das Ganze recht gut mit der Verarbeitung einer sequentiellen Datei vergleichen (vgl. Abb. 3.5). Wie war das doch gleich noch: Zunchst musste eine solche Datei meistens mit Hilfe einer speziellen Anweisung (z.B. open) geffnet werden. Anschlieend kann die Datei solange Satz fr Satz gelesen werden, bis das Dateiende erreicht wird, was meistens mit Hilfe einer Schleife realisiert wird. Ist das Ende der Datei erreicht, dann springen wir aus der Schleife heraus und schlieen die Datei mit Hilfe einer entsprechenden Anweisung (z.B. close) wieder. Dieses Verfahren aus der Zeit von Adam und Eva (EVA = Eingabe Vearbeitung Ausgabe) kommt nun auch hier wieder zum Tragen, denn die eben beschriebenen Praktiken aus einem typischen EDV-Einfhrungskurs lassen sich auch jetzt ganz gut anwenden. Was sich hier allerdings von unseren vielleicht ersten EDV-Gehversuchen unterscheidet ist, dass wir in der Oracle-Datenbank keine sequentielle Datei zum ffnen haben, wobei sich dieses Dilemma durch ein wenig Kreativitt leicht berwinden lsst, indem wir uns die sequentielle Datei als logisches Gebilde und als Endergebnis unserer durchgefhrten Abfrage vorstellen.

310

Abfragen

ffnen der Datei

Ende der Datei erreicht?

Nein

Datensatz lesen

Ja

Schlieen der Datei


Abbildung 3.5: Sequentielles Verarbeiten einer Datei

Es geht im Folgenden nun wirklich darum, in einem ersten Schritt die bentigte Ergebnismenge bereitzustellen und diese Menge im zweiten Schritt sequentiell in einem der Abbildung 3.5 entsprechenden Schema zu verarbeiten. Natrlich ist die Behandlung von Cursorn an dieser Stelle im Buch eine kleine Gratwanderung, denn eigentlich gehrt das Thema komplett in den Bereich PL/ SQL-Programmierung und wird von mir auch dort noch einmal aufgegriffen. Auf der anderen Seite passt es aber auch hier ganz gut ins Konzept, wo es darum geht die Mglichkeiten aufzuzeigen, die Sie zum ndern bzw. Verarbeiten der in der Datenbank gespeicherten Daten haben. Ich werden also hier und jetzt die Verwendung eines Cursors nur an kleineren Beispielen demonstrieren und Sie fr weitergehende Informationen zum Weiterlesen des Buches ntigen. Kehren wir nun zunchst noch einmal an den Ort der Lschabfragen zurck. Dort hatten wir die Aufgabenstellung, Datenstze mit ungltigen Personalstammdaten aus der Datenbank zu lschen. Dabei bestand beispielsweise beim Verarbeiten der Gehaltdaten das Problem darin, fr den jeweiligen Gehaltsdatensatz den lschrelevanten Zustand der Personalstammdaten zu erkennen, was damals mit Hilfe entsprechender Unterabfragen realisiert wurde. Diesmal wollen wir anders vorgehen und zunchst eine Ergebnismenge mit allen fehlerhaften Personalstammdaten erzeugen und diese zusammen mit allen anderen zugehrigen Stzen aus anderen Tabellen whrend der sequentiellen Verarbeitung der Ergebnismenge lschen. Im Listing 3.25 finden Sie das hierzu bentigte Skript, wobei ich mich wegen der besseren bersicht auf das Lschen der Personalien und Gehlter beschrnkt habe.
declare cursor falsche_personalien is select persnr, name from personalien a

nderungsabfragen

311

where geschlecht not in ('M','W','1','2') for update of a.persnr; in_record falsche_personalien%rowtype; begin open falsche_personalien; loop fetch falsche_personalien into in_record; exit when falsche_personalien%notfound; delete gehalt where persnr = in_record.persnr; delete personalien where current of falsche_personalien; end loop; close falsche_personalien; end;
Listing 3.25: Lschen von Daten mit Hilfe eines PL/SQL-Cursors

Nachdem Sie nun durch das Listing 3.25 das vollstndige Programm kennen, wollen wir es als nchstes Stck fr Stck auseinandernehmen und dabei auch die eine oder andere Variante darstellen, wobei Sie im PL/SQL-Kapitel weitere Mglichkeiten zur Verarbeitung der Cursormenge finden. Zunchst einmal besteht unser Skript aus einem Deklarations- und einem Ausfhrungsteil, der zwischen den Schlsselwrtern begin und end programmiert wird. Der Deklarationsteil wird mit dem Schlsselwort declare eingeleitet und dient zur Anlage aller bentigten Variablen und eben auch zur Definition des eigentlichen Cursors.
cursor falsche_personalien is select persnr, name from personalien a where geschlecht not in ('M','W','1','2') for update of a.persnr;

Dieser wird mit Hilfe des Schlsselwortes cursor definiert, dem der im Skript eindeutige und ansonsten frei vergebare Name des Cursors folgt unter dem das Cursorobjekt im weiteren Skript angesprochen werden kann. Die Kodierung der dem Cursor zugrundeliegenden Abfrage erfolgt nach dem Schlsselwort is und entspricht einer normalen Auswahlabfrage. Bei Bedarf kann der definierte Cursor einen Zeiger auf eine der an der Abfrage beteiligten Tabellen mitfhren, indem Sie am Ende der Abfrage die for update of-Klausel angeben.

312

Abfragen

for update of a.persnr

Wie Sie schon wissen, fhrt diese Anweisung zum einen zur Sperrung der gelesenen Datenstze, aus der dem Feld zugrundeliegenden Tabelle. Zum anderen erffnet die Klausel Ihnen innerhalb der Cursorprogrammierung allerdings auch die Mglichkeit, die zum Feld gehrende Tabelle fr die aktuell gelesene Datenzeile auf besonders einfache Weise zu ndern. Mit Hilfe bzw. hinter der for update of-Klausel mssen Sie ein Feld, ggf. zusammen mit dem jeweiligen zugewiesenen Aliasnamen, aus derjenigen Tabelle angeben, fr die Sie den angedeuteten internen nderungszeiger wnschen. Das hier genannte Feld dient also wirklich nur als Platzhalter zur Erstellung eines Zeigers auf die zugehrige Tabelle und muss selbst im Rahmen des Programms nicht verndert werden. Im Umkehrschluss heit das natrlich auch, dass die zu ndernden Felder nicht unbedingt in dieser Klausel aufgezhlt werden mssen; falls Sie es dennoch tun, dann hat das hchstens Dokumentationscharakter.
in_record falsche_personalien%rowtype

Neben dem Cursor definieren wir noch eine Struktur mit dem Namen in_record. Sie dient uns spter zur Aufnahme der einzelnen gelesenen Datenstze und aufgrund der Verwendung des Ausdrucks falsche_personalien%rowtype enthlt die Struktur automatisch alle innerhalb des Cursors selektierten Spalten. Innerhalb des begin und end-Blocks befindet sich das eigentliche Programm, das im Prinzip dem Schema der Abbildung 3.5 entspricht. Zunchst wird der Zugriff auf die Ergebnismenge erffnet, indem der Cursor mit einem open-Befehl geffnet wird. Am Ende des Programms wird er wieder mit Hilfe des close-Kommandos geschlossen.
open falsche_personalien; loop fetch falsche_personalien into in_record; exit when falsche_personalien%notfound; ... end loop; close falsche_personalien;

Dazwischen erfolgt das Abrufen der einzelnen Datenstze mit Hilfe einer Endlosschleife. Innerhalb der wird zunchst versucht, den nchsten Datensatz der Ergebnismenge vom Cursor mit Hilfe des fetch-Befehls abzurufen und die zugehrigen Daten in die hierfr definierte Struktur in_record zu kopieren. Die danach folgende Programmzeile fhrt zum Ausstieg aus der eigentlichen Endlosschleife, wenn der vorherige fetch-Befehl keinen Datensatz mehr geliefert hat, weil bereits alle Datenstze des Cursors verarbeitet wurden. Im weiteren Innenleben der Schleife findet dann die eigentliche Verarbeitung statt.

nderungsabfragen

313

delete gehalt where persnr = in_record.persnr; delete personalien where current of falsche_personalien;

Zunchst lschen wir mit Hilfe einer gewhnlichen delete-Anweisung die Gehaltsdaten fr die aktuell geladene Personalnummer. Anhand der zugehrigen whereBedingung knnen Sie auch erkennen, wie Sie auf die einzelnen in der Struktur in_record gespeicherten Elemente zugreifen knnen, wobei das Verfahren den Struktur- und Elementnamen und einen Punkt als Trennzeichen zu verwenden in vielen Programmiersprachen verwendet wird. Unsere Struktur enthlt wegen des select-Befehls bei der Cursordefinition also insgesamt folgende zwei Elemente.
in_record.persnr in_record.name

Die zweite delete-Anweisung dient zum Lschen der Personalstammdaten. Hierbei benutzen wir eine besondere Form der where-Klausel, die mit dem bei der Cursordefinition angelegten Datensatzzeiger zusammenarbeitet und automatisch den zugehrigen Datensatz aus der entsprechenden Tabelle selektiert. Die current ofKlausel stellt also eine Verbindung zwischen dem aktuellen Datensatz des Cursors und der mit Hilfe der for update of-Klausel spezifizierten Tabelle dar. Varianten Statt der verwendeten Struktur in_record knnen Sie die einzelnen Spalten des Cursors natrlich auch in gewhnliche Variablen laden. Hierbei mssen Sie fr jede im Cursor definierte Spalte eine entsprechende Variable definieren, die Sie innerhalb des fetch-Befehls hinter dem into-Schlsselwort in der richtigen Reihenfolge aufzhlen mssen.
declare cursor falsche_personalien is select persnr, name from personalien a where geschlecht not in ('M','W','1','2') for update of a.persnr; xpersnr varchar2(11); xname varchar2(30); begin open falsche_personalien; loop fetch falsche_personalien into xpersnr, xname; exit when falsche_personalien%notfound; delete gehalt

314

Abfragen

where persnr = xpersnr; delete personalien where current of falsche_personalien; end loop; close falsche_personalien; end;

Auer, dass Sie jetzt statt der Strukturelemente die entsprechenden Variablen verwenden mssen, ndert sich im Programm ansonsten gar nichts. Ich persnlich bevorzuge das Laden des gesamten Datensatzes in eine Struktur, da diese Verfahrensweise resistenter gegen nderungen bzw. Erweiterungen ist. Verwenden der Pseudo-Spalte rowid In unserem letzten Beispiel haben wir die Gehaltsdaten mit Hilfe des ersten Teils des Primrschlssels gelscht. Was ist aber zu tun, wenn die im Cursor verarbeitete Tabelle berhaupt keinen eindeutigen Schlssel besitzt und wir die nderungsoperation trotzdem mglichst effizient durchfhren wollen? In dem Fall kann der Zugriff ber die Pseudospalte rowid eine mgliche Lsung sein, dann der Zugriff auf einen Datensatz ber die rowid ist der schnellste aller zur Zeit mglichen Varianten.
SQLWKS> select rowid, persnr, lfdnr, gab from gehalt; ROWID PERSNR LFDNR GAB ------------------ ----------- ---------- -------------------AAAApHAADAAABESAAA 7000001 0 01-JAN-90 AAAApHAADAAABESAAB 7000002 0 01-APR-98 AAAApHAADAAABESAAC 7000002 0 01-APR-99 AAAApHAADAAABESAAD 7000003 0 01-AUG-99 AAAApHAADAAABESAAE 7000004 0 01-APR-98 AAAApHAADAAABESAAF 7000004 0 01-JUL-98 AAAApHAADAAABESAAG 7000004 0 01-APR-99 AAAApHAADAAABESAAJ 7000005 0 01-FEB-99 AAAApHAADAAABESAAK 7000005 0 01-SEP-99 ... 49 rows selected.
Listing 3.26: Anzeige der fr jeden Datensatz verfgbaren rowid

Bei dieser rowid handelt es sich um eine Art Datensatznummer, mit deren Hilfe jeder Datensatz einer Tabelle direkt und eindeutig identifiziert werden kann. Technisch handelt es sich hierbei um einen String, der hexadezimale Werte enthlt und den Sie innerhalb von Abfragen in der select-Klausel und in jeder where-Klausel verwenden knnen.
select * from gehalt where rowid = 'AAAApHAADAAABESAAK';

nderungsabfragen

315

Dank der teilweise gut funktionierenden impliziten Konvertierung verschiedener Datentypen funktioniert das eben gezeigte Beispiel einwandfrei. Innerhalb von Oracle, beispielsweise in einem PL/SQL-Programm, knnen Sie den Datentyp rowid zum Speichern der Datensatzzeiger verwenden. Wenn Sie einen solchen Wert in einem anderen Programm (z.B. Cobol, Visual Basic oder SQR) speichern mssen, dann knnen Sie hierzu eine normale Zeichenkette bzw. Stringvariable verwenden. Allerdings bin ich kein Freund impliziter Datentypskonvertierungen, da ich hierbei schon meinen Lehrgeldbeitrag geleistet habe. Bei Programmierarbeiten fr ein anderes Datenbanksystem wurde noch innerhalb des Projekts durch das Einspielen eines Miniupdates die implizite Konvertierung von Zeitwerten in Strings und umgekehrt gendert, so dass viele Teile des Programms anschlieend nicht mehr korrekt funktionierten. Diese Erfahrung hat mich saniert und deshalb empfehle ich auch Ihnen, nach Mglichkeit Datentypumwandlungen immer explizit vorzunehmen. In unserem konkreten Beispiel der rowid sieht das Ganze dann folgendermaen aus.
select rowidtochar(rowid) from gehalt where rowid = chartorowid('AAAApHAADAAABESAAK');

Wie sie sehen, existiert fr die Umwandlung der Pseudospalte rowid in Zeichnketten und umgekehrt die Funktionen rowidtochar bzw. chartorowid und immer wenn Sie solche Werte mit Hilfe von Stringvariablen zwischenspeichern mssen, dann sollten Sie von diesen beiden Funktionen gebrauch machen. Um die konkrete Anwendung der rowid-Verwendung kurz zu demonstrieren, kehren wir noch einmal zu unserem letzten Cursor-Beispiel zurck und ndern die dem Cursor zugrundeliegende Abfrage, indem wir anstelle der current of-Klausel die rowid fr den Zugriff auf die Personalstammdaten verwenden (vgl. Listing 3.27).
declare cursor falsche_personalien is select rowid, persnr from personalien a where geschlecht not in ('M','W','1','2'); xpersnr varchar2(11); xrowid rowid; begin open falsche_personalien; loop fetch falsche_personalien into xrowid, xpersnr; exit when falsche_personalien%notfound; delete gehalt where persnr = xpersnr;

316

Abfragen

delete personalien where rowid = xrowid; end loop; close falsche_personalien; end;
Listing 3.27: Verwendung der rowid in unserem Lschcursor

Wie Sie in dem Beispiel sehen, laden wir den Datensatzzeiger fr die selektierten Personalstammstze im Rahmen des fetch-Befehls in die Variable xrowid. Da die vom Datentyp rowid ist, kann der vom Cursor gelieferte Wert ohne Konvertierung gespeichert werden. Ein paar Zeilen spter verwenden wir diese rowid, um den zugehrigen Personalstammdatensatz zu lschen. Wenn Sie jetzt die Stirn runzeln, dann ist das sicherlich nicht ganz unberechtigt, denn im Augenblick stellt sich im Vergleich zu den vorherigen Lsungen fr die beschriebene Aufgabenstellung schon die Frage, warum wir uns das Ganze hier freiwillig ein wenig komplizierter gestalten. Absetzen zwischenzeitlicher commits Die Antwort auf diese Frage will ich Ihnen natrlich nicht schuldig bleiben, denn wie fr die meisten Dinge gibt es auch hierfr mal wieder einen Grund. Bei langlaufenden Programmen oder wenn whrend der Verarbeitung Unmengen von Daten gendert werden ist die Datenbank manchmal dankbar, wenn in regelmigen Abstnden commit-Befehle abgesendet werden. Wie Sie aber schon wissen, fhrt ein commit-Befehl zur Aufhebung der for update-Sperrungen und damit auch zur Inaktivierung des current of-Datensatzzeigers. Sollen nun im Rahmen eines nderungscursors ein commit-Befehl in regelmigen Abstnden abgesetzt werden, dann mssen Sie auf die Verwendung der current ofKlausel verzichten und den Zugriff auf die zu ndernden Daten beispielsweise mit Hilfe der rowid selbst in die Hand nehmen.
declare cursor falsche_personalien is select rowid, persnr from personalien a where geschlecht not in ('M','W','1','2'); xpersnr varchar2(11); xrowid rowid; ct number; begin open falsche_personalien; loop fetch falsche_personalien into xrowid, xpersnr; exit when falsche_personalien%notfound;

nderungsabfragen

317

delete gehalt where persnr = xpersnr; delete personalien where rowid = xrowid; if ct > 10 then ct := 1; commit; else ct := ct +1; end if; end loop; close falsche_personalien; end;
Listing 3.28: Verwenden von commit-Befehlen in einem nderungscursor

Im letzten Beispiel wird mit Hilfe eines Zhlers (vgl. Listing 3.28) nach jeweils zehn verarbeiteten Datenstzen ein commit-Befehl abgesetzt, um die bis dahin genderten Datensatze unwiderruflich in die Datenbank zurckzuschreiben. Damit das mglich ist, mssen wir, wie schon gesagt, auf die for update- und damit auf auf die current of-Klausel verzichten und verwenden stattdessen die rowid fr den direkten Zugriff auf die Tabelle. Natrlich knnten wir auch die Personalnummer, die schlielich Primrschlssel der Personalstammdaten ist, verwenden, was im Endergebnis nicht viel aber vielleicht doch ein klitzekleines bisschen langsamer gewesen wre. Verwenden der returning-Klausel Manchmal bentigt man in seinem Programm noch einmal die durch die Abfrage genderten Werte, was blicherweise zum Lesen der Tabelle vor dem Lschen bzw. direkt nach dem ndern oder Einfgen fhrt. Oracle bietet Ihnen aber die Mglichkeit, diese Werte im Rahmen der Abfrage direkt in entsprechende Variablen zu berfhren, so dass sich das nochmalige bzw. vorherige Lesen der zugehrigen Tabelle erbrigt. Die als Beispiel hierzu passende Aufgabenstellung verlangt, die aktuellen Gehlter unserer Mitarbeiter um fnf Prozent zu erhhen, wobei wir eine Hinweismeldung bentigen, wenn der Mitarbeiter nach der Gehaltserhhung die Grenze von 6000,00 (_ oder DM?) bersteigt. Die Lsung dieser Aufgabenstellung finden Sie im Listing 3.29 und daran im Anschluss finden Sie die Beschreibung der neuen Programmteile.
set serveroutput on; declare

318

Abfragen

cursor neues_gehalt is select a.rowid, a.* from gehalt a, bvs b where b.persnr = a.persnr and b.lfdnr = a.lfdnr and b.austrt is null and a.gab = (select max(gab) from gehalt a1 where a1.persnr = a.persnr and a1.lfdnr = a.lfdnr ) for update of a.gehalt; gehalt_rec neues_gehalt%rowtype; ngehalt number(7,2); begin open neues_gehalt; loop fetch neues_gehalt into gehalt_rec; exit when neues_gehalt%notfound; update gehalt set gehalt = gehalt * 1.05 where rowid = gehalt_rec.rowid returning gehalt into ngehalt; if ngehalt > 6000 and gehalt_rec.gehalt < 6000 then dbms_output.put_line('Gehalt, alt: ' || to_char(gehalt_rec.gehalt,'99990.00') || ' neu: ' || to_char(ngehalt,'99999.99')); end if; end loop; close neues_gehalt; end;
Listing 3.29: Verwenden eines Cursors mit anschlieender Prfung der neuen Feldwerte

Schon wieder ein neuer Cursor und schon wieder schleichen sich damit fast zwangslufig neue PL/SQL-Sprachelemente ins Programm. Zunchst einmal mchte ich an dieser Stelle nur kurz darauf hinweisen, dass Sie mit Hilfe des im Programm verwendeten Pakets dbms_output Hinweismeldungen generieren knnen, die nach der Programmausfhrung am Bildschirm angezeigt werden, sofern zustzlich die Option set serveroutput on gesetzt wurde. Mehr zu dem Thema erfahren Sie allerdings erst im weiteren Verlauf des Buches im Kapitel PL/SQL-Programmierung.

nderungsabfragen

319

Auerdem denke ich, dass ich die dem Cursor zugrundeliegende Abfrage, die mal wieder den aktuellsten Datensatz fr alle Mitarbeiter ohne Austrittsdatum liefert auch nicht mehr beschreiben muss, da Sie die in der oder hnlicher Form schon mehrmals in diesem Workshop gesehen haben. Worauf es in dem Beispiel hauptschlich ankommt, ist der Abschluss der update-Anweisung, wodurch der neue Gehaltsbetrag in die dafr angelegte Variable ngehalt kopiert wird.
returning gehalt into ngehalt;

Hierdurch ersparen wir uns den erneuten Zugriff auf die Gehaltsdaten und knnen mit Hilfe der nachfolgenden if-Abfrage prfen, ob mit dem neuen Gehaltsbetrag die sechstausender-Grenze berschritten wurde. In dem Fall geben wir mit Hilfe der Paketprozedur put_line eine Hinweismeldung aus, so dass das Ganze zumindest in meinem aktuellen Datenbestand folgendermaen aussieht.
Gehalt, alt: Gehalt, alt: 5899.00 neu: 5800.00 neu: 6193.95 6090.00

Zusammenfassung Die letzten Seiten des Buches konnte sicherlich nur einen Eindruck vermitteln, was mit Hilfe eines PL/SQL-Cursors alles mglich ist, denn allumfassend kann man die Mglichkeiten gar nicht beschreiben, da sie nahezu endlos sind. Auf der anderen Seite haben Sie sicherlich auch gemerkt, dass die klassischen datensatzbezogenen Verarbeitungsformen (Satz lesen, Verarbeitung durchfhren ...) auch im SQL-Zeitalter nicht unbedingt vllig berholt sind, denn manchmal bietet diese Technik Vorteile gegenber der rein mengenmigen Verarbeitung mit Hilfe der standardmigen SQL-Befehle. Damit mchte ich dieses Thema dann auch zunchst einmal mit der Anmerkung abschlieen, dass Sie weitere Beispiele und Varianten zu Cursorn und PL/SQL-Programmen im weiteren Verlauf dieses Workshops finden werden.

3.3.6

Transaktionen

Das ist mal wieder ein Kapitel, das man durch einen Ausflug in die zugehrige Datenbanktheorie einleiten knnte. Allerdings will ich es auch hier bei einer einfachen Definition belassen und eine Transaktion einfach als eine logisch zusammengehrende Einheit einer oder mehrerer Datenbankoperationen beschreiben. Ein hierfr viel gelittenes aber einfaches Beispiel ist das einer Bankberweisung. Wie Sie alle wissen, wandert im Rahmen einer solchen berweisung ein Geldbetrag von einem auf ein anderes Konto, was wir uns technisch als Ergebnis zweier updateAnweisungen vorstellen knnten. Auerdem wird der Geldfluss selbst noch einmal in ein Journal eingetragen, so dass zustzlich auch noch eine Einfgeanweisung entsteht.
update umsaetze set betrag = betrag + 100 where konto = '1234';

320

Abfragen

update umsaetze set betrag = betrag 100 where konto = '2345'; insert into journal(konto_von, konto_bis, betrag) values ('1234', '2345', 100);

Diese beiden update-Anweisungen und die insert-Anweisung gehren zusammen wie das berhmte Pech und Schwefel, d.h. es sollen entweder alle oder keine der nderungsabfragen in der Datenbank ausgefhrt. Dabei ist es gleichgltig, warum eine der drei Abfragen auf der Strecke bleibt, d.h. selbst wenn ein technischer Defekt dafr verantwortlich ist, dass die zweite nderung abbricht, dann muss die schon ausgefhrte erste Anweisung beim Wiederhochfahren der Datenbank (recovery) zurckgerollt werden. Etwas allgemeiner betrachtet, weisen Transaktionen insgesamt folgende Eigenschaften aus:

: :

Wie schon gesagt, werden alle Anweisungen innerhalb einer Transaktion wie eine logische Einheit betrachtet, d.h. das DBMS fhrt entweder alle oder gar keine Anweisungen der Transaktion aus. Eine Transaktion berfhrt die Datenbank von einem konsistenten Zustand in den nchsten konsistenten Zustand. Zwischenzeitlich auftretende Inkonsistenzen sind dabei fr andere Transaktion unsichtbar. Auf unser berweisungsbeispiel bertragen bedeutet das, dass sich fr alle anderen Anwender die Salden der an der berweisung beteiligten Konten nicht ndern, solange die Transaktion nicht abgeschlossen wurde. Transaktionen laufen isoliert ab, d.h. jede einzelne Transaktion luft quasi in einem simulierten Einbenutzerbetrieb. Die Ergebnisse einer erfolgreich beendeten Transaktion sind dauerhaft in der Datenbank gespeichert.

: :

Das bisher Gesagte ist strenggenommen zunchst einmal keine spezielle Facette einer Oracle-Datenbank, sondern resultiert aus den allgemeinen Beschreibungen bzw. Anforderungen von Datenbanksystemen, d.h. wir werden uns erst jetzt im zweiten Schritt anschauen, welche Auswirkungen das Ganze in unserem OracleDBMS hat. Im Unterschied zu manch anderen Datenbanksystemen ist die Anwendung des Transaktionsprinzips in Oracle keine optionale Komponente, die bei Bedarf eingeschaltet oder in besonderen Situationen auch weggelassen werden kann. In Oracle beginnt eine Transaktion immer mit der ersten auszufhrbaren SQL-Anweisung und endet entweder erfolgreich oder bricht wegen einer Fehlersituation ab bzw. wird am Ende oder zwischendurch explizit zurckgerollt. Die Aufforderung eine Transaktion erfolgreich abzuschlieen erfolgt mit Hilfe der Anweisung commit, weshalb wir im bisherigen Verlauf des Workshops diesen Befehl auch immer als letzte Anweisung in allen unseren Beispielen verwendet haben. Zurckgerollt wird eine Transaktion entweder automatisch durch einen

nderungsabfragen

321

Fehler oder manuell durch das Absetzen des rollback-Kommandos. Ich habe mir angewhnt, alle SQL-Befehle, ausgenommen von Auswahlabfragen, mit einer commit-Anweisung abzuschlieen, was strenggenommen eigentlich nicht notwendig ist, da alle Anweisungen, die zur Anlage oder nderung von Datenbankobjekten fhren, auch eine implizite commit-Anweisung beinhalten. Die Transaktionen solcher sogenannten DDL-Anweisungen (DDL = Data Definition Language), mit denen Sie beispielsweise Tabellen, Indexe oder Prozeduren in der Datenbank anlegen, werden nach der erfolgreichen Ausfhrung immer sofort automatisch abgeschlossen, weshalb das manuelle Nachschicken einer commitAnweisung eigentlich doppelt gemoppelt ist. Aber auf diese Weise gewhnt man sich aber an die ansonsten notwendige commit-Verwendung. Ich habe schon Kollegen zur Fragestunde im Bro gehabt, die nicht verstanden haben, warum sich Ihre Session immer beim Absetzen einer alter table-Anweisung aufhngt, was konkret daran lag, dass bei einer vorherigen nderungsabfrage auf diese Tabelle der abschlieende commit-Befehl vergessen wurde. Deswegen konnte das Objekt zur Strukturnderung nicht gesperrt werden, was zum Warten der Session mit dem alter table-Befehl fhrt, so dass es den Anschein hat, als htte sich die Sitzung aufgehngt. Wenn man von anderen Datenbanksystemen nach Oracle wechselt, dann muss man sich unter Umstnden an dieses gezwungene Transaktionsprinzip erst ein wenig gewhnen. Das gilt vor allem dann, wenn Sie bisher Batchprogramme oder Skripte mit endlosen vielen SQL-Anweisungen erstellt haben. Sie knnen sich sicherlich vorstellen, dass das mitfhren einer Transaktion mit allen seinen Protokollen und Garantien einen gewissen Overhead darstellt. Aus diesem Grund sollten Sie falls mglich Ihre Programme oder Skripte durch den Einbau gelegentlicher commit-Anweisungen verschnern. Falls das nicht geht, dann mssen Sie in jedem Fall darauf achten, dass alle Ihre nderungen in das bei der Transaktion verwendeten Rollback-Segement passen. Das ist allerdings kein Grund, jetzt alle definierten Segmente bermig gro zu gestalten, denn Sie knnen das whrend der Transaktion bzw. das whrend Ihres Programmlaufs zu verwendende Segment zuweisen. Rollback-Segment zuweisen Hierzu existiert in Oracles SQL-Sprachumfang die Anweisung set transaction in der Variante use rollback segment, hinter der Sie den Namen des zu verwendenden Rollback-Segements spezifizieren mssen. Das nachfolgende Beispiel verwendet fr die durchzufhrende nderungstransaktion das Rollback-Segment mit dem Namen rb0.
set transaction use rollback segment rb0; update gehalt set gehalt = gehalt * 1.05; rollback;

Implizite commits Wie schon gesagt, fhren DDL-Anweisungen nach deren Ausfhrungen zu impliziten commit-Anweisungen. Das mssen Sie natrlich auch in Ihren Programmen

322

Abfragen

bercksichtigen, denn wenn Sie zwischendurch einmal eine neue Arbeitstabelle oder einen Index definieren, dann werden wegen des damit implizit verbundenen commits auch alle anderen bisher durchgefhrten nderungsabfragen abgeschlossen. Aus dem Grund kann es sinnvoll sein, alle bentigten DDL-Anweisungen an den Programmanfang zu verlagern. Auerdem macht es Sinn, bei verwendeten Tools oder Programmiersystemen (z.B. Cobol oder SQL) einmal nachzuschauen, was diese Programmsysteme bei einem Abbruch oder dem normalen Programmende in der Datenbank tun. So fhrt ein SQR-Programm beispielsweise automatisch ein commit in der Datenbank durch, wenn das gestartete Programm bzw. die zugehrige SQR-Workbench normal beendet wird, wobei bei einem Programmabbruch automatisch ein rollback abgesetzt wird. Lngere Lesekonsistenz erzwingen Oracle garantiert fr die in einer Abfrage selektierten Daten natrlich ganz von alleine, dass diese untereinander konsistent sind, wobei diese Konsistenz auf der anderen Seite nur fr eine logische Sekunde gegeben sein muss, denn im Mehrbenutzerbetrieb kann es natrlich vorkommen, dass just in dem Moment jemand anderes nderungen an dem von Ihnen gelesenen Datenbestand vornimmt. Aus dem Grund kann es natrlich leicht passieren, dass wenn Sie in einem Programm die Tabellen in einem spteren Schritt noch einmal lesen, die Daten nicht mehr vorhanden sind oder andere Werte enthalten. Sofern dieser in einer Mehrbenutzerumgebung eigentlich ganz normale Sachverhalt nicht tragbar ist, dann gibt es neben dem Kopieren aller bentigter Daten noch die Mglichkeit, auch Ihre Auswahlabfragen in einer Transaktion ablaufen zu lassen, so dass wegen der Transaktion fr die gesamte Ausfhrungsdauer Lesekonsistenz garantiert wird. Auch hierfr knnen Sie die Anweisung set transaction allerdings diesmal in der Variante read only verwenden. Wir wollen das im Folgenden ausprobieren, wozu Sie wieder zwei Sitzungen Ihres SQL-Editors starten mssen. Mit Hilfe der ersten Sitzung fhren wir eine einfache Abfrage auf einen Personalstammdatensatz aus, wobei wir die Abfrage diesmal innerhalb einer Lesetransaktion laufen lassen.
set transaction read only; select name from personalien where persnr = '7000002';

Mit Hilfe der Abfrage, die wegen der Anwendung des set transaction-Befehls innerhalb reiner Lesetransaktion luft, erhalten Sie das nachfolgend gezeigte Ergebnis.
NAME -------------------------------------------------Karlo,Armin 1 row selected.

nderungsabfragen

323

Wechseln Sie nun zur zweiten Sitzung Ihres SQL-Editors und schicken Sie von dort folgende nderungsabfrage an Ihre Datenbank.
update personalien set name = 'Karlo,Armin-Helgo' where persnr = '7000002'; commit;

Hierdurch wird der Name des soeben selektierten Mitarbeiters gendert, was aber fr unsere erste Arbeitssitzung zunchst unsichtbar bleibt, d.h. wenn Sie von dort die eben gezeigte Auswahlabfrage noch einmal absenden, so werden Sie trotz der zwischenzeitlich durchgefhrten nderung wieder den alten Namen des Mitarbeiters erhalten.
SQLWKS> select name 2> from personalien 3> where persnr = '7000002'; NAME -------------------------------------------------Karlo,Armin 1 row selected.

Dieser Zustand bleibt so lange erhalten, bis Sie die Lesetransaktion wieder mit Hilfe einer commit-Anweisung abschlieen, d.h. erst die nun folgende Abfrage fhrt zur Anzeige des mittlerweile neuen Namens des Mitarbeiters.
SQLWKS> commit; Statement processed. SQLWKS> select name 2> from personalien 3> where persnr = '7000002'; NAME -------------------------------------------------Karlo,Armin-Helgo 1 row selected.

Die Verwendung von Sicherungspunkten Die Anlage von Sicherungspunkten innerhalb von Transaktionen mchte ich Ihnen der Vollstndigkeit halber nicht verschweigen. Solche Sicherungspunkte knnen Sie in Ihrem Ablauf zusammen mit einem rollback-Kommando anspringen, so dass Sie in Ihrem Programm auf bestimmte Fehlersituationen mit dem Zurcksetzen aller Aktionen seit dem Erreichen eines Sicherungspunktes reagieren knnen. Das Setzen eines Sicherungspunktes erfolgt mit Hilfe der Anweisung savepoint, dem Sie einen innerhalb der Transaktion eindeutigen Namen anhngen mssen.
savepoint A

324

Abfragen

<Irgendwelche SQL-Anweisungen> savepoint B <Weitere SQL-Anweisungen> if <Bedingung> then rollback to savepoint B

Ist der von Ihnen vergebene Sicherungsname nicht eindeutig, sondern beispielsweise immer der gleiche, dann verschiebt sich die Sicherungsmarke beim Ablauf des Programms dynamisch auf die zuletzt erreichte savepoint-Marke. Mehr hierzu finden Sie spter in diesem Workshop, wenn im Rahmen der PL/SQL-Einfhrung die Fehlerbehandlung besprochen wird.

3.4

Tuning von Abfragen

Damit erreichen wir ein eigentlich sehr komplexes und bizarres Thema, das schlichtweg mit der Fragestellung beginnt, woran man eine zu tunende Abfrage berhaupt erkennen kann. Die Antwort auf dieses Frage ist allerdings simpel, denn im Regelfall macht sich eine Abfrage mit Tuningpotential nicht von alleine bemerkbar. Solange eine Abfrage oder ein Programm berhaupt fertig wird, befindet man sich bei diesem Thema in einem der hufig stattfindenden Znkereien zwischen Fachabteilung und EDV-Betrieb, wobei den einen immer alles viel zu langsam und den anderen immer alles viel zu aufwendig ist. Ich selbst musste hierbei schon so mache Gemtsschlappe hinnehmen, beispielweise einmal nachdem ich eine Dialogabfrage von ber eine Minute auf zwei Sekunden beschleunigt hatte und die erste Reaktion der Fachabteilung die war, warum das nicht gleich so gemacht wurde und ob man es nicht noch etwas schneller machen knnte; doch nun zurck zum eigentlichen Thema. Worauf ich mit meiner Einleitung eigentlich nur hinweisen wollte ist, dass man zum einen pauschal niemals wei, ob eine Abfrage oder ein Programm schneller laufen kann und dass es zum anderen Ansichts- bzw. Empfindungssache ist, ob etwas schnell genug oder zu langsam ist. Manchmal sagt einem die Erfahrung, das eine bestimmte Aktivitt in der Datenbank schneller gehen sollte, wohingegen man manchmal auch nach stundenlangem Forschen und Rumprobieren keine bessere Variante aus dem rmel zu schtteln vermag. Auerdem muss man sich meiner Meinung nach auch immer fragen, was eine marginale Laufzeitverbesserung kosten darf. Ich finde es jedenfalls sinnlos, wenn die Laufzeit eines ber Nacht laufendes Batchprogramms von 30 auf 25 Minuten verkrzt wurde und man dafr auf der anderen Seite 2 Tage experimentieren musste, zumal man nicht ausschlieen kann, dass das Laufzeitverhalten bei einer sich ndernden Datenkonstellation in eine andere Richtung kippt (altes Verfahren 40 Minuten; neues jetzt auf einmal 55 Minuten).

Tuning von Abfragen

325

Das ist im brigen in Wirklichkeit vor allem bei relationalen Datenbanksystemen ein weiteres Problem. Das Antwortzeitverhalten einer solchen Datenbank verndert sich bei wachsenden Datenbestnden eigentlich niemals linear zum Bestand. Manchmal habe ich sogar den Eindruck, dass zwischen Antwortzeit und Datenbankgre nicht einmal ein expotentieller Zusammenhang besteht, sondern das hierbei schlichtweg Schwellenwertproblematiken auftreten. Das resultiert aus Erfahrungen, wo Abfragen bei einer bestimmten Datensatzanzahl x Minuten, bei doppelter Satzanzahl 3x Minuten und bei Erreichen der dreifachen Datenmenge gar nicht mehr liefen. Sie sehen also, dass sie es hierbei mit einem Thema zu tun haben, fr des es keine globalen Patentrezepte gibt und bei dem alle Grenzen, Rahmenbedingungen und Regeln dauernd in Bewegung sind bzw. laufend irgendwelchen Vernderungen unterliegen. Trotzdem gibt es eine Reihe von Grundstzen und Regeln, deren Einhaltung fast immer zu ordentlich laufenden Abfragen fhren, und die in den folgenden Abschnitten zusammen mit einigen persnlichen Erfahrungen zum besten geben mchte. Sie finden im Folgenden also kein Kochrezept fr die perfekte Abfrage, sondern lediglich eine Reihe von Zutaten, die vielfach kombinierbar zu leckeren Gerichten fhren. Daneben empfehle ich jedem interessierten den Genuss bestimmter Teile der Oracle-Dokumentation. Konkret finden Sie im Buch Oracle8 Concepts das Kapitel The Optimizer und im gesamten Buch Oracle8 Tuning weitergehende Informationen zu diesem Themenkomplex. In der 8i-Version heit das zuletzt genannte Buch etwas anders. Sie finden die Informationen dort unter der berschrift Oracle8i Designing and Tuning for Performance.

3.4.1

Abfrageoptimierung

In nahezu allen relationalen Datenbanksystemen werden die von Ihnen erstellten Abfragen nicht einfach so ausgefhrt, sondern zunchst von einem sogenannten Optimierer (engl. Optimizer) analysiert und anschlieend entsprechend eines bei der Analyse erstellten Ausfhrungsplans ausgefhrt. Auch in Oracle8 gibt es einen solchen Optimierer, wobei der mal wieder zur Entscheidungsqual des Benutzers in zwei unterschiedlichen Varianten betrieben werden kann. Regelbasierte Optimierung Hierbei wird der Ausfhrungsplan mit Hilfe festgelegter Regeln und Prioritten der verwendeten Operationen erstellt. Solche Regeln ergeben sich zum Teil aus den zu den Operationen gehrenden mathematischen Grundlagen oder resultieren aus dem Einsatz konkreter Verfahrensweisen zur Ausfhrung bestimmter Operationen, beispielsweise der Auswahl geeigneter Verknpfungsalgorithmen in Abhngigkeit vorhandener Indexstrukturen. Kostenbasierte Optimierung Im Unterschied zur regelbasierten Optimierung basiert die kostenbasierte Variante auf der Ausnutzung statistischer Daten ber die Datenbank. Dies impliziert, dass

326

Abfragen

die kostenbasierte Optimierung nur dann funktionieren kann, wenn die zugehrigen Statistiken angelegt und in Bezug auf den Datenbankstand halbwegs aktuell sind. Generell versucht die kostenbasierte Optimierung, die zur Ausfhrung der Abfrage bentigten Ressourcen zu minimieren. Die Anlage solcher Statistiken erfolgt mit Hilfe des Befehls analyze table, dem zunchst einmal der Name der zu analysierenden Tabelle folgt. Anschlieend mssen Sie bestimmen, ob Sie die statistischen Daten exakt berechnet oder durch Analyse eines vorzugebenden Prozentsatzes der Datenstze geschtzt werden soll. Die beiden nachfolgenden Beispiele zeigen die Verwendung des analyze table-Befehls zum Anlegen der Statistiken.
analyze table gehalt compute statistics; analyze table personalien extimate statistics sample 20 percent;
Listing 3.30: Anlegen der Statistiken mit dem Befehl analyze table

Klar ist eigentlich, dass die Erstellung berechneter Statistiken bei groen Tabellen wesentlich lnger dauern kann als deren Schtzung. Neben diesen Statistiken spielen bei der kostenbasierten Optimierung zustzlich auch noch sogenannte Histogramme eine Rolle, mit deren Hilfe die Wertverteilung spezieller Felder dargestellt werden knnen. Die Kenntnis ber diese Wertverteilung ist wichtig wenn es darum geht, die Verwendung bestimmter Indexe oder Join-Algorithmen festzulegen. Oracle selbst empfiehlt in der Dokumentation die Anlage solcher Histogramme zumindest fr alle in einem Index vorkommenden Spalten, da diese Felder blicherweise hufig innerhalb der Auswahl- und Verknpfungsbedingungen von Abfragen verwendet werden. Solche spaltenbezogenden Statistiken werden ebenfalls mit einer Variante des analyze table-Befehls erzeugt. Das nachfolgende Beispiel zeigt deren Anlage fr alle Indexspalten.
analyze table gehalt compute statistics for all indexed columns;

Wenn spezielle Spalten regelmig in Auswahlbedingungen vorkommen und nicht in irgendwelchen Indices vorhanden sind, dann knnen Sie fr diese Spalte Statistikinformationen sammeln, in dem Sie das analyze-Kommando in der folgenden Variante verwenden.
analyze table gehalt compute statistics for columns gehalt, zulage;

Mit Hilfe des letzten Beispiels werden Informationen ber die Verteilung der Spalten gehalt und zulage in das Datendictionary eingetragen, wo sie dem kostenbasierten Optimierer anschlieend zur Verfgung stehen.

Tuning von Abfragen

327

Sollten Sie sich irgendwann einmal gegen kostenbasierte Optimierung entscheiden, was allerdings aufgrund der zur Zeit absehbaren Produktentwicklung nicht zu empfehlen ist, dann besteht eine der notwendigen Manahmen darin, die vorhandenen Statistikinformationen aus der Datenbank zu lschen. Auch das knnen Sie ebenfalls mit Hilfe eines analyze-Kommandos bewerkstelligen:
analyze table gehalt delete statistics;

Wie Sie den bisherigen Beispielen entnehmen konnten, so ist das Sammeln und Speichern von Statistiken fr eine konkrete Datenbank mit vielleicht einigen hundert Tabellen eine aufwendige Angelegenheit. Hierbei mssen Sie auch bercksichtigen, dass diese Statistiken zumindest fr diejenigen Tabellen, die starken Vernderungen unterworfen sind, regelmig aktualisiert werden mssen, was ganz einfach durch ein erneutes Ausfhren des analyze-Befehls passiert. Zur Anlage von Statistiken finden Sie in der Oracle-Datenbank im brigen das Paket dbms_utility, in dem Sie mit der dort enthaltenden Prozedur analyze_schema ein kleines Hilfsmittel zur Hand haben, um alle im Schema enthaltenen Objekte zu analysieren. Die Anlage weiterer Statistiken fr einzelne oder alle Spalten wre dann Feinarbeit, wobei ich dennoch eine andere Verfahrensweise vorschlagen wrde. Mit Hilfe einer separaten Tabelle wrde ich alle zu analysierenden Objekte namentlich oder mit Hilfe von Regeln speichern. Im zweiten Schritt wrde ich eine Prozedur erstellen, deren Aufruf zur Analyse aller spezifizierten Objekte fhrt. Etwas hnliches finden Sie im brigen in den Beispielen zur PL/SQL-Programmierung, wo wir mit Hilfe einer Prozedur die Neuerstellung aller Indices oder die Aktualisierung aller Benutzerrechte veranlassen. Optimierungsart festlegen Die Festlegung der verwendeten Optimierungsart kann von Ihnen auf drei unterschiedliche Arten beeinflusst werden:

Festlegen der zu verwendenden Variante in der Initialisierungsdatei der Datenbankinstanz. Hierbei knnen Sie die zu verwendende Methode mit Hilfe des Parameters optimizer_mode in der Initialisierungsdatei festlegen. Die hier eingestellte Methode (Standard: choose) entspricht damit dem Standardwert der Datenbankinstanz. Sie knnen die Variante fr die Lebensdauer einer Datenbanksitzung ndern, indem Sie die Sitzungsparameter mit Hilfe einer alter session-Anweisung ndern. Wie das Ganze aussieht, das knnen Sie dem folgenden Beispiel entnehmen:
alter session set optimizer_mode = choose;

Als letzte Variante haben Sie noch die Mglichkeit, die zu verwendende Optimierung in der einzelnen SQL-Abfrage festzulegen, indem Sie innerhalb der Abfrage sogenannten Hints verwenden. Solche Hints sehen aus wie Kommentare und werden innerhalb der Abfrage platziert und vom Optimierer entsprechend

328

Abfragen

ausgewertet. Das folgende Beispiel erzwingt fr die zugehrigen Auswahlabfrage eine regelbasierte Optimierung:
select /*+ rule */ name from personalien

Insgesamt kennt Oracle die in der Tabelle 3.9 beschriebenen Optimierungsarten:


Optimierungsart choose Beschreibung Hierbei wird die Auswahl zwischen regel- und kostenbasierter Optimierung vom System getroffen, was in der Praxis zur kostenbasierten Variante fhrt, wenn die dafr bentigten Statistiken vorhanden sind. In diesem Modus wird bezglich der Zeit optimiert, die zur Bereitstellung des gesamten Ergebnisses bentigt wird. Im Unterschied zu all_rows wird jetzt dahingehend optimiert, erste Ergebnisse mglichst schnell anzuzeigen. Somit eignet sich das Verfahren bei bestimmten Abfragevarianten berhaupt nicht. Ein Beispiel dafr sind gruppierende Abfragen, bei denen zunchst alle Einzelstze bereitgestellt werden mssen, bevor die Gruppierfunktion berhaupt gestartet werden kann. fhrt zur regelbasierten Optimierung.

all_rows first_rows

rule

Tabelle 3.9: Optimierungsarten in einer Oracle-Datenbank

Gerade durch die zuletzt gezeigten Hints knnen Sie neben der Optimierungsart noch weiteren Einfluss auf die Arbeitsweise des Optimierers nehmen, was sich blicherweise in einem anderen bzw. entsprechend genderten Ausfhrungsplan niederschlgt. Im nchsten Schritt werden wir uns zunchst anschauen, auf welche Art- und Weise Sie sich den vom Optimizer ermittelten Ausfhrungsplan anschauen knnen und im Anschluss daran, also im bernchsten Kapitel, finden Sie einige Grundregeln fr die Erstellung effizienter Abfragen und erst danach folgt in diesem Buch eine bersicht ausgewhlter Hints. Wenn Sie jetzt von mir die Empfehlung fr oder gegen die eine oder andere Optimierungsart erwarten, dann muss ich Sie enttuschen, da ich mich hier auf Basis meiner bisherigen beruflichen Erfahrung nicht festlegen kann bzw. will. So wie ich bestimmte Dokumentationen bzw. die Hinweise von Oracle verstanden habe, handelt es sich bei der kostenorientierten Variante um das modernere Verfahren, wobei die regelbasierte Variante sogar nur noch aus Grnden der Kompatibilitt enthalten ist und einige Objekte und Methoden (z.B. Bitmap-Index oder HaschJoin) berhaupt nicht untersttzt. Trotzdem kenne ich eine Reihe von groen Datenbanken, die auch in der Version 8 immer noch regelbasiert betrieben werden, denn vor allem bei groen Datenbanken ist eine Optimiererumstellung aufwendiger, als mal eben das dbms_utility-Paket einzusetzen. Nach meiner bisherigen Erfahrungen hat es in kleineren Datenbanken zumindest keine negativen Auswirkungen, wenn man mit der Durchfhrung einfacher analayze-Szenarien die kostenbasierte Optimierung einschaltet.

Tuning von Abfragen

329

Bei groen Datenbanken (viele Tabellen mit ber 100.000 bis 3 Mio. Datenstzen) ist das allerdings nicht ganz so einfach, sondern hier muss man schon genauer hinschauen, welche Statistikvarianten bentigt werden bzw. welche Histogramme zustzlich erstellt werden mssen. Die alleinige Trivialanalyse des Schemas mit dem dbms_utility-Paket hat hier einmal in einem mir bekannten Fall den Abfragegau ausgelst, indem ohne sonstige nderungen zuvor im Sekundenbereich laufende Abfragen auf einmal ber 30 Minuten fr die gleiche Arbeit brauchten. Fr unser Schema sollten Sie jetzt allerdings einmal diese Analyse durchfhren, damit Ihnen im Folgenden das volle Aktionsspektrum des Optimierers zur Verfgung steht. Hierzu knnen Sie das dbms_utility-Paket folgendermaen verwenden.
execute dbms_utility.analyze_schema('UBEISPIEL','compute');

3.4.2

Ausfhrungsplne

Wie schon gesagt, erstellt der Optimierer unabhngig von der gewhlten bzw. eingestellten Methode vor der Ausfhrung einer Abfrage einen zugehrigen Ausfhrungsplan. Mit Hilfe eines speziellen Befehls knnen Sie diese Ausfhrungsplne sichtbar machen, wobei die Analyse des Ausfhrungsplans oftmals Hinweise ber mgliche Verbesserungen Ihrer Abfrage liefert. Planungstabelle erstellen Bevor Sie jedoch erstmalig einen solchen Ausfhrungsplan erstellen knnen, mssen Sie dafr sorgen, dass in Ihrer Datenbank bzw. Ihrem Schema eine geeignete Tabelle vorhanden ist, in der die einzelnen Schritte des Plans gespeichert werden. Konkret heit diese Tabelle plan_table und kann bei Bedarf mit einem standardmig vorhandenem Skript erstellt werden. Sie finden das Skript in der Datei UTLXPLAN.SQL, die sich normalerweise im \RDBMSxx\ADMIN-Unterverzeichnis Ihrer Oracleinstallation befindet.
SQLWKS> desc plan_table Column Name Null? ------------------------------ -------STATEMENT_ID TIMESTAMP REMARKS OPERATION OPTIONS OBJECT_NODE OBJECT_OWNER OBJECT_NAME OBJECT_INSTANCE OBJECT_TYPE OPTIMIZER SEARCH_COLUMNS ID PARENT_ID Type ---VARCHAR2(30) DATE VARCHAR2(80) VARCHAR2(30) VARCHAR2(30) VARCHAR2(128) VARCHAR2(30) VARCHAR2(30) NUMBER(38) VARCHAR2(30) VARCHAR2(255) NUMBER NUMBER(38) NUMBER(38)

330

Abfragen

POSITION COST CARDINALITY BYTES OTHER_TAG PARTITION_START PARTITION_STOP PARTITION_ID OTHER

NUMBER(38) NUMBER(38) NUMBER(38) NUMBER(38) VARCHAR2(255) VARCHAR2(255) VARCHAR2(255) NUMBER(38) LONG

Listing 3.31: Struktur der Hilfstabelle zur Visualisierung eines Abfrageplans

Wie Sie dem Listing 3.31 entnehmen knnen, enthlt die mit dem Skript erstellte Ergebnistabelle eine ganze Reihe von Feldern, weshalb von einer manuellen Anlage abzuraten ist. Ausfhrungsplan erstellen Ist die bentigte Hilfs- bzw. Ergebnistabelle erst einmal angelegt, dann steht dem Erstellen der Ausfhrungsplne nichts mehr im Wege. Konkret existiert hierzu der Befehl explain plan, der zusammen mit der zu analysierenden Abfrage verwendet und nach folgendem Schema angewendet wird.
explain plan set statement_id = 'TEST' for <SQL-Abfrage>

An dem Schema erkennen Sie, dass neben der Vorgabe der zu analysierenden SQLAbfrage noch das Setzen des in die Ergebnistabelle bernommenen Feldes statement_id eine gewisse Rolle spielt. Theoretisch knnen Sie mehrere Ausfhrungsplne nebeneinander vorhalten, die sptere bei der Auswertung mit Hilfe des hier vergebenen Wertes auseinandergehalten werden knnen. Auf der anderen Seite lsst die gerade schematisch dargestellte Verwendungsform Schlimmes befrchten, was meiner Meinung nach auch zutrifft, denn wenn Sie eine Analyse mit immer der gleichen Id durchfhren, dann werden die unterschiedlichen Plne vermischt, was eine nachtrgliche Auswertung sicherlich vereitelt. Ich habe mir daher angewhnt, die Analyse einer Abfrage mit folgendem Skript aufzurufen:
truncate table plan_table; explain plan for <SQL-Abfrage>

Wie das Ganze nun wirklich konkret funktioniert, das knnen sie am Beispiel des nchsten Listings (vgl. 3.32) sehen, indem ein Ausfhrungsplan fr unsere typische Gehaltsabfrage erstellt wird.
truncate table plan_table; explain plan for

Tuning von Abfragen

331

select persnr, lfdnr, gab from gehalt a where gab = (select max(gab) from gehalt b where b.persnr = a.persnr and b.lfdnr = a.lfdnr and b.gab <= sysdate )
Listing 3.32: Erstellen eines Ausfhrungsplans fr eine Gehaltsabfrage

Als Ergebnis erhalten Sie, wie das nchste Listing (vgl. 3.33) zeigt, eine Hand voll Zeilen in der Hilfstabelle plan_table, und es geht im nchsten Abschnitt nun darum, diese Weissagungen des Systems zu deuten bzw. zu interpretieren.
SQLWKS> select operation, options 2> from plan_table; 3> OPERATION OPTIONS ------------------------------ -----------------------------SELECT STATEMENT FILTER TABLE ACCESS FULL SORT AGGREGATE INDEX RANGE SCAN 5 rows selected.
Listing 3.33: Ergebnis des im Listing 3.32 erstellten Ausfhrungsplans

Ausfhrungsplan lesen Nach der Erstellung eines Ausfhrungsplans knnen Sie ihn mit Hilfe der Ergebnistabelle auswerten, was jedoch einfacher gesagt als getan ist. Zum einen stellt sich die Frage, welche Felder man sich hierbei anschauen soll, denn die Tabelle enthlt insgesamt ber 20 Werte und zum anderen macht es Sinn, die erstellten Datenstze in einer bestimmten Reihenfolge auszuwerten. Hierzu finden Sie sowohl in der Oracle-Dokumentation als auch in nahezu jedem sonstigen Handbuch hnliche Beispiele, die sich zumindest in Bezug auf die verwendete Auswahl und Verkettung nicht unterscheiden. Ich habe mich fr die folgende (vgl. Listing 3.34) leicht abgewandelte Version aus den Oracle-Tuningunterlagen entschieden.
select level, position, lpad(' ',2*(level-1)) || operation || ' '|| options || ' ' || object_name as q_plan from plan_table start with id = 0 connect by prior id = parent_id
Listing 3.34: Hierarchische Auswertung des Ausfhrungsplans

332

Abfragen

Wenn Sie sich noch einmal die in der Planungstabelle enthaltenen Datenstze anschauen, dann werden Sie feststellen, dass die dort gespeicherten Datenstze mit Hilfe der Felder id und parent_id verkettet sind, d.h. Sie finden hier wieder ein klassisches Einsatzgebiet der connect by-Anweisung. Wie Sie schon dem Listing 3.33 entnehmen konnten, werden die wesentlichsten Zugriffsinformationen mit Hilfe der drei Spalten operation, options und object_name beschrieben. Mit Hilfe der dargestellten Abfrage werden diese drei Zeilen zu einer Ausgabezeile zusammengefasst, wobei die entsprechend ihrer hierarchischen Einordnung mit Hilfe des Ausdrucks
lpad(' ',2*(level-1))

eingerckt werden. Zur weiteren Orientierungshilfe habe ich mich dafr entschieden, zustzliche noch die beiden Felder level und position mit auszugeben, wobei die Position die Ausfhrungsreihenfolge bei ansonsten gleichem Level beschreibt.
LEVEL POSITION Q_PLAN ---------- ---------- ------------------------------------------------1 SELECT STATEMENT 2 1 FILTER 3 1 TABLE ACCESS FULL GEHALT 3 2 SORT AGGREGATE 4 1 INDEX RANGE SCAN GEHALT_PK 5 rows selected.
Listing 3.35: Auswertung des Ausfhrungsplans fr die Abfrage aus Listing 3.32

Die eigentliche Abarbeitung des im Listing 3.35 gezeigten Plans erfolgt von unten nach oben bzw. bei gleicher Ebene entlang der Positionsnummer. Was hiermit gemeint ist, wird sptestens klarer, wenn man fr diesen Plan einen zugehrigen Ausfhrungsbaum zeichnet, den Sie der Abbildung 3.6 entnehmen knnen.

FILTER

TABLE ACCESS FULL GEHALT

SORT AGGREGATE

INDEX RANGE SCAN GEHALT_PK

Abbildung 3.6: Baumdarstellung unsers Abfrageplans aus Listing 3.35

Dem Baum entsprechend wird unsere Abfrage von unten nach oben bzw. links nach rechts abgearbeitet, d.h. zunchst wird die Gehaltstabelle wegen fehlender Selektionskriterien vollstndig gelesen, was als Eingabe fr einen Filterprozess dient. Die andere Eingabe dieses Filters ist das Ergebnis einer Sortieroperation, die wiederum die Ergebnisse aus dem Lesen des Index gehalt_pk verarbeitet.

Tuning von Abfragen

333

Es mag sein, dass diese Plne bzw. deren Darstellen manchen Vollbluttechnikern zu oberflchlich sind, wobei ich entgegenhalten muss, dass zumindest mir diese Plne in den meisten Fllen gereicht haben, um die eventuell vorhandenen Schwachstellen in der Abfrage schnell zu finden und fr Abhilfe zu sorgen, denn folgende und meist gravierende Einflussfaktoren auf die Abfragegeschwindigkeit knnen Sie einem solchen Plan entnehmen:

: : :

Verwendet Oracle zur Verarbeitung vorhandene Indices bzw. die richtigen Indices oder werden permanent bzw. oft die gesamten Tabellen gelesen? Werden die Tabellen in einer sinnvollen Reihenfolge gelesen? Werden Views, vor allem welche mit umfangreichen Ausgaben, materialisiert, d.h. es wird nicht das in der View gespeicherten SQL-Statement verwendet, sondern die Ergebnismenge der View wird weiterverarbeitet? Auf welche Weise werden die Tabellen miteinander verknpft? Bei der kostenbasierten Optimierung werdend die Kosten jedes Verarbeitungsschrittes in der Spalte cost gespeichert, d.h. Sie haben hierdurch ein weiteres Kriterium in der Hand, um nach besonders teuren Arbeitsschritten zu suchen, um diese beispielsweise mit Hilfe eines zustzlichen Index vielleicht zu verbilligen.

: :

Die Kontrolle bzw. Anpassung der eben aufgezhlten Einflussfaktoren reicht in den meisten Fllen aus, damit aus lahmen Krcken ordentlich laufende Abfragen werden. Viel mehr zu tun ist sowieso ein zweischneidiges Schwert, denn zum einen kann sich das Verhalten des Optimierers bei sich ndernden Daten- bzw. Mengenkonstellationen extrem verndern oder Oracle reagiert in einer zuknftigen Version auf Ihre Spezialeinstellung gar nicht mehr oder zumindest in einer anderen Weise. Neben dem Ausfhrungsplan gibt es gibt im brigen noch weitere Mglichkeiten, dem System Informationen ber die Ausfhrung von SQL-Statments abzuringen. Eine dieser Mglichkeiten besteht in der Verwendung von TKPROF, wobei Sie Informationen hierber beispielsweise in der Oracle-Dokumentation im Kapitel The SQL Trace Facility and TKPROF des Buchs Oracle8 Tuning, das sich bei Interesse generell zu lesen lohnt, finden. Wie Sie ansonsten schon an unserem bisherigen kleinen Beispiel sehen konnte, werden im Ausfhrungsplan neben den gelesenen Tabellen oder Indices auch die Methoden dargestellt, mit denen diese Objekte oder zuvor erstellte Ergebnisse verarbeitet werden. Konkret werden diese Informationen im Ausfhrungsplan fr jeden Einzelschritt mit bis zu drei Angaben dargestellt. Als Erstes finden Sie im Feld operation die durchgefhrte Operation. Bei einigen dieser Operationen enthlt der Plan nhere Hinweise ber den verwendeten Algorithmus, die im Feld options gespeichert werden. Oftmals werden die einzelnen Operationen zusammen mit spezifischen Datenbankobjekten (z.B. Tabellen oder Indexen) ausgefhrt, wobei Sie in dem Fall den Namen des verwendeten Objekts in der Spalte object_name vorfinden.

334

Abfragen

Die nachfolgende Tabelle 3.10 zeigt Ihnen eine bersicht der wichtigsten Operationen und Optionen. Beachten Sie hierbei, dass bestimmte Operationen an vorhandene Datenbankoptionen (z.B. Bitmap-Index) oder an spezielle Optimierverfahren (z.B. keine Hash-Verknpfung im regelbasierten Betrieb) gebunden sind.
Operation BITMAP Option Beschreibung Die Verwendung der besonderen Bitmap-Indexe wird im Ausfhrungsplan entsprechend gekennzeichnet. CONVERSION TO ROWIDS CONVERSION FROM ROWIDS INDEX SINGLE VALUE> INDEX RANGE SCAN INDEX FULL SCAN MERGE OR CONNECT BY berfhrung der Datensatzzeiger rowid in Bitmaps (TO ROWIDS) oder umgekehrt (FROM ROWIDS). Zugriff bzw. Verwenden des Bitmap-Index in der vorgegebenen Art und Weise (vgl. INDEX-Operation).

Mischen der Bitmaps aus einem RANGE SCAN zu einem neuen Bitmap. Bitweise oder-Verknpfung fr ein Bitmap. Hierarchische Auflsung einer Datenmenge, was durch die entsprechende SQL-Anweisung ausgelst wird. Verschmelzen zweier Ergebnismengen, d.h. diese Operation entspricht quasi der Mengenoperation union-all.

CONCATENATION

COUNT

STOPKEY

fhrt zum Abbruch der Abfrage, wenn eine bestimmte Anzahl von Ergebnissen ermittelt wurde. Wird durch Verwendung der Pseudospalte rownum in der where-Bedingung ausgelst. Ausfhren eines Datensatzfilters aufgrund diverser Anforderungen, beispielsweise der Verwendung einfacher Auswahlanweisungen oder als Ergebnis durchgefhrter Verknpfungen. Anzeige, dass die selektierten Datenstze gesperrt werden. Resultiert aus der Verwendung der for update-Klausel in einer Abfrage. Ein Verfahren zur Verknpfung von Tabellen mit Hilfe einer Hash-Funktion.

FILTER

FOR UPDATE

HASH JOIN ANTI

Bei der Anti-Verknpfung muss als Ergebnis das brig bleiben, was man erhlt, wenn man von der gesamten primren Tabelle diejenigen Datenstze herausstreicht, die erfolgreich verknpft werden konnten. Der Verknpfungsoperator not in kann zusammen mit einer Unterabfrage zu einer Anti-Join-Verknpfung fhren.

Tuning von Abfragen

335

Operation

Option SEMI

Beschreibung Durchfhrung eines Semi-Joins nach der HashMethode. Beim sogenannten Semi-Join werden aus der verknpften Tabelle keine eigentlichen Daten bentigt, d.h. die Verknpfung erfolgt nur als Selektionskriterium fr die primre Tabelle. Ein Semi-Join kann durch eine exists-Unterabfrage entstehen. liest die gesamte Tabelle in der durch den Index vorgegebenen Sortierreihenfolge, d.h. das System erspart sich hierdurch einen Sortiervorgang. Auswahl eines einzelnen Datensatzes ber den angegebenen eindeutigen Index. Ermittlung einer oder mehrere Datenstze, indem der spezifizierte Index fr einen bestimmten Bereich aufsteigend durchlaufen wird. Wie oben, nur dass der Index hierbei absteigend durchlaufen wird. Ergebnis der entsprechenden Mengenoperation. Beim Merge-Join liegen die zu verknpfenden Mengen entsprechend der Verknpfungsfelder sortiert vor. Beide Mengen werden sequentiell durchlaufen und dabei entsprechend synchronisiert.

INDEX

FULL SCAN

UNIQUE SCAN RANGE SCAN

RANGE SCAN DESCENDING INTERSECTION MERGE JOIN

OUTER ANTI SEMI MINUS NESTED LOOPS

Durchfhrung eines Outer-Joins mit der eben beschriebenen Technik. Durchfhrung eines Merge-Anti-Joins (s.a. HashJoin). Durchfhrung eines Merge-Semi-Joins (s.a. HashJoin). wird durch die entsprechende Mengenoperation ausgelst. besondere Technik zur Durchfhrung einer Verknpfung. Hierbei ist eine der beiden Tabellen die fhrende und bei deren Verarbeitung werden die passenden Datenstze aus der anderen Tabelle hinzugefgt.

OUTER REMOTE SEQUENCE SORT AGGREGATE

Durchfhren eines Outer-Joins mit dem NestedLoops-Verfahren. Die Daten werden ber einen Link aus einer anderen Datenbank abgerufen. Abrufen einer Sequence-Nummer. Verfahren zur Lieferung einer einzelnen Datenzeile. Wird durch Verwendung einer Aggregatfunktion ohne group by-Klausel ausgelst.

336

Abfragen

Operation

Option GROUP BY JOIN UNIQUE ORDER BY

Beschreibung Sortierung und Gruppierung der Datenstze. Sortierung der Datenstze als Vorbereitung eines sogenannten Merge-Joins. Eliminierung doppelter Datenstze, z.B. wegen Verwendung der distinct-Klausel. Sortierung der Datenstze, z.B. wegen vorgegebener order by-Klausel. Lesen aller Datenstze einer Tabelle. ermglicht einen besonderen Zugriff bei Tabellen, die auf diese Weise angelegt wurde. Besondere Zugriffsform bei gestreut gespeicherten Tabellen. Direkter Zugriff auf einzelne Datenstze ber den Datensatzzeiger. Ausfhrung der union-Anweisung, d.h. die Ergebnisse zweier Abfrage werden gemischt. Falls Sie statt union all nur union verwendet haben, so fhrt das System anschlieend noch die Operation sort unique aus, um die doppelten Stze auszuschlieen. Ausfhrung einer View, d.h. die von der View gelieferten Datenstze werden abgerufen und zwischengepeichert.

TABLE ACCESS

FULL CLUSTER HASH BY ROWID

UNION-ALL

VIEW

Tabelle 3.10: bersicht der wichtigsten Operationen und Optionen eines Ausfhrungsplans

3.4.3

Ein paar Grundregeln fr die Erstellung von Abfragen

Auch wenn es kein Patentrezept gibt, so gibt es dennoch ein paar Grundregeln, deren Einhaltung dazu fhrt, dass die erstellten Abfragen ganz gut laufen. Bei der kostenorientierten Optimierung mssen Sie zustzlich noch darauf achten, dass aktuelle Statistiken und Histogramme fr die wichtigen Selektionsbegriffe vorhanden sind und nur im Ausnahmefall sollten Sie davon Gebrauch machen, die Arbeit des Optimierers durch Verwendung der sogenannten Hints zu beeinflussen. Eine Beschreibung von einigen dieser Optimiererschalter, die im brigen bei der regelbasierten Optimierung ignoriert werden, finden Sie im nchsten Kapitel, doch nun zunchst einmal zu den von mir angedeuteten Regeln, die Sie nach Mglichkeit beachten sollten. Indices Verwendet Oracle die richtigen Indices bzw. sind fr die abgefragten bzw. verknpften Spalten berhaupt welche bzw. vernnftige Indices definiert. Sicherlich beinhaltet jeder zustzliche Index einen gewissen Overhead, und trotzdem sollten Sie vor allem bei greren Tabellen und fr die innerhalb von Selektionen hufig

Tuning von Abfragen

337

verwendeten Feldern einen Index anlegen, denn bei groen Tabellen ist jeder TABLE ACCESS FULL ein Zeitrisiko. Bei der Anlage der Indices sollten Sie darauf achten, dass die selektivsten Spalten alle in einem Index zusammenhngend enthalten sind, wobei der Index zustzlich mit einem der verwendeten Felder beginnt, d.h. die Kette der Indexfelder passt zu den verwendeten Suchbegriffen. Beispielsweise kann ein Index ber die Spalte name bei der Namenssuche verwendet werden, wohingegen dies bei einem zusammengesetzten Index mit den Feldern geschl, name nicht mglich ist, wohingegen das bei umgekehrter Feldreihenfolge wiederum denkbar wre. Anders ausgedrckt kann ein Index so lange bzw. bis zu dem Indexfeld benutzt werden, wie die verwendeten Suchbegriffe lckenlos der gleichen Reihenfolge entsprechen. Vermeiden Sie die Anlage unntiger Indices. Vor allem manche Standardprogramme generieren fr ihre Suchbegriffe Indexe in jeglicher Begriffskombination. Bei der regelbasierten Optimierung geht das meistens ins Auge und fhrt zur Verwendung einer ungeeigneten Indexdatei. Welcher Index bei der kostenbasierten Optimierung verwendet wird, hngt auch wieder von vorhandenen Statistiken ab und trotzdem glaube ich, dass man mit Einzelindices fr die wichtigsten Suchbegriffe oftmals besser fhrt. Die beim Zugriff bzw. der Selektion verwendeten Indices knnen Sie mit Hilfe des Ausfhrungsplans kontrollieren. Bei der kostenbasierten Optimierung sollten Sie sich dabei allerdings nicht wundern, wenn bei kleinen Tabellen niemals der Zugriff ber einen Index erfolgt. Regelbasierte Optimierung Bei der regelbasierten Optimierung knnen Sie Reihenfolge der verarbeiteten Tabellen mit Hilfe der from-Klausel steuern, wobei die Verarbeitung von unten nach oben bzw. rechts nach links erfolgt. Durch die Umsortierung der from-Klausel knnen Sie also erheblichen Einfluss auf den Ausfhrungsplan und damit auch auf die Ausfhrungsgeschwindigkeit der Abfrage nehmen. Bei der regelbasierten Optimierung mssen sie sich also berlegen, welche Tabelle Ihre Abfrage treiben soll und welche anderen Tabellen selektiv hinzugefgt werden sollen. Was man bei der dieser Optimierung auerdem meistens sehr schn im Ausfhrungsplan ist, ist die Verwendung vorhandener Indices, da diese Regel ist eben Regel nach bestimmten Kriterien verwendet werden, obwohl das aufgrund der Datenmenge oder anderer Einschrnkungen in diesem Fall vielleicht gar nicht sinnvoll ist, weshalb sie der kostenbasierte Optimierer im gleichen Fall auch eben nicht benutzt. Joins und Mengenoperationen Vermeiden Sie nach Mglichkeit Outer-Joins und, von der union-Verknpfung einmal abgesehen, umfangreiche Mengenoperationen. Gerade bei der Anwendungsentwicklung knnen Sie Outer-Join-Problematiken oftmals durch separate Datenbankzugriffe oder durch das Erstellen und Aufbereiten von Arbeitstabellen umgehen, indem Sie beispielsweise die Personalien und vielleicht vorhandene

338

Abfragen

Qualifikationen separat lesen anstelle die Daten in einem Zug mit Hilfe einer Outer-Join-Verknpfung zu lesen. Im brigen gilt das eben Gesagte auch, wenn eine Abfrage irgendwann einmal aufgrund ihres Umfangs nicht mehr so richtig laufen will. Manchmal ist es besser eine Abfrage in mehrere Einzelschritte zu zerlegen, d.h. mit Hilfe eines Skripts und einzelnen Abfragen oder Cursorn wird zunchst eine Arbeitstabelle gefllt, die anschlieend mit Hilfe einer einfachen Auswahlabfrage ausgelesen wird. Unterabfragen Vermeiden Sie Unterabfragen mit den Verknpfungsopratoren in oder not in, die sich meistens durch exists bzw. not exists-Abfragen und einer damit verbundenen besseren Performance ersetzen lassen. Beachten Sie dabei auch, dass die Selektion von etwas Nichtvorhandenem im brigen meistens aufwendiger ist, als die Existenz eines Datensatzes zu berprfen. Wenn es dann aber schon sein muss, dann sollten Sie wenigstens darauf achten, dass die in der Unterabfrage erzeugte Datenmenge mglichst klein bleibt. Ebenso sollten Sie darauf achten, dass auch die Schachtelungstiefe von Unterabfragen mglichst gering ist. Manche Unterabfragen knnen auch durch echte Joins ersetzen werden. Das bringt oftmals Laufzeitvorteile, weshalb ich schon bei den nderungscursorn gesagt hatte, dass vor allem nderungsabfragen, die wegen der fehlenden fromKlausel nur mittels Unterabfragen eingeschrnkt werden knnen, als Cursor manchmal besser laufen, da Sie hierbei statt der Unterabfrage einen echten Join verwenden knnen. Betrachten Sie hierzu einmal folgendes Beispiel, indem alle Personalien ausgewhlt werden sollen, die ebenfalls ber ein Beschftigungsverhltnis verfgen. Wenn man diese Aufgabenstellung spontan angeht, so kommt einem vielleicht die nachfolgende Lsung in den Sinn, die Auswahl mit Hilfe einer Unterabfrage durchzufhren, wobei Sie den zugehrigen Ausfhrungsplan im Listing 3.36 finden.
select a.* from personalien a where exists(select 1 from bvs b where b.persnr = a.persnr) LEVEL POSITION Q_PLAN ---------- ---------- ------------------------------------------1 1 SELECT STATEMENT 2 1 FILTER 3 1 TABLE ACCESS FULL PERSONALIEN 3 2 INDEX RANGE SCAN BVS_PK
Listing 3.36: Ausfhrungsplan fr eine Unterabfrage

In dem Beispiel werden die Personalien mit Hilfe des Primrschlssels der Beschftigungsverhltnisse gefiltert. Besser als ein Filter wre aber die Verwendung eines echten Join-Algorithmus, den Sie durch folgende Umstellung der Abfrage erreichen

Tuning von Abfragen

339

(vgl. Listing 3.37), wobei Sie hierbei zustzlich bercksichtigen, dass jeder Mitarbeiter mit einem Beschftigungsverhltnis auch in jedem Fall einen Datensatz mit der laufenden Nummer 0 besitzt.
select a.* from personalien a ,bvs b where b.persnr = a.persnr and b.lfdnr = 0 LEVEL POSITION Q_PLAN ---------- ---------- ------------------------------------------1 1 SELECT STATEMENT 2 1 NESTED LOOPS 3 1 TABLE ACCESS FULL PERSONALIEN 3 2 INDEX UNIQUE SCAN BVS_PK
Listing 3.37: Ausfhrungsplan nach Auflsung der Unterabfrage in einen echten Join

Nach Umstellung der Abfrage sieht auch der Ausfhrungsplan vllig anders aus. Auch jetzt werden die Personalien vollstndig gelesen, wobei nun durch den Join vom Typ NESTED LOOPS bei jedem Datensatz direkt im Primrschlssel der Beschftigungsverhltnisse nachgeschaut wird, ob dieser Satz auszuwhlen ist oder nicht. Aufbau der Abfrage Es gibt Kollegen, die wissen gar nicht, dass der Auswahlbefehl select und nicht select distinct heit und mal abgesehen davon, dass die distinct-Klausel durchaus in der Lage ist, einen vorhandenen Abfragefehler zu verschleiern, so fhrt sie in jedem Fall zu einem vielleicht berflssigen SORT UNIQUE Arbeitsschritt. Generell gilt, dass gut strukturierte Abfragen oftmals besser laufen, als inhaltlich gleiche Spagettiabfragen. Gut strukturiert beinhaltet hierbei allerdings weniger die uerliche Formatierung, die fhrt im Regelfall zu weniger Fehlern, sondern die Verwendung unntiger bzw. ungnstiger Konstruktionen. So sollten Sie beispielsweise aufpassen, wenn Sie bei Auswahl- oder Verknpfungsbedingungen auf das Phnomen der impliziten Datentypkonvertierung setzen, da das zum Ausschluss vorhandener Indexdateien fhren kann. So fhrt die Anweisung where zeichenspalte = 1234 intern zu der Ausfhrung where to_number(zeichenspalte) = 1234 und damit zur Nichtverwendung eines eventuell vorhandenen Index, wobei Letzteres sogar immer dann gilt, wenn die Felder der Tabelle nicht direkt, sondern erst nach dem Durchschleusen durch eine Funktion bzw. innerhalb eines Ausdrucks verwendet werden. Ich habe hierfr im Folgenden einmal drei exemplarische Beispiele aufgefhrt und Sie werden sich wundern, wie viel man mit solchen Kleinigkeiten manchmal bewirken kann.
where zeichenspalte = to_char(1234) statt where zeichenspalte = 1234 where wertspalte > 3455 -1

340

Abfragen

statt where wertspalte +1 > 3455 where name like 'ABC%' statt where substr(name,1,3) = 'ABC'

Generell gilt, dass Sie einzelne Felder im Rahmen einer Verknpfung mglichst direkt und nicht erst nach einer mehr oder weniger umfangreichen Umformatierung verwenden sollten.
where a.datum = b.datum statt where to_char(a.datum, 'YYYY.MM.DD') = to_char(b.datum, 'YYYY.MM.DD')

Handelt es sich bei dem Datumsfeld beispielsweise um ein Indexfeld, welches im besonderen Fall nur bis zum enthaltenen Monat abgefragt werden muss, dann knnen Sie durch die folgende Abfrage bzw. Umformatierung ggf. die Verwendung eines INDEX RANGE SCAN erreichen.
where a.datum between to_date('2000.01.01', 'YYYY.MM.DD') and to_date('2000.01.31', 'YYYY.MM.DD') statt where to_char(a.datum, 'YYYY.MM' = '2000.01'

Versuchen Sie auch die Verwendung umfangreicher in-Listen zu vermeiden, wobei es sogar oft so ist, dass der Verwendungszwang solcher Listen auf ein Problem im Datenmodell hinweist.
where kst in ('PERS', 'EDV', 'UMT', 'VERT')

Die soeben aufgezhlten Kostenstellen gehren vielleicht zu einem Bereich, so dass es bei mehreren Bereichen entsprechend viele unterschiedlichen Kostenstellenlisten gibt. In dem Fall fehlt im Datenmodell wohl eher eine Bereichstabelle, mit der sich Kostenstellen zu einem Bereich zuordnen lassen, so dass die Abfrage anschlieend folgendermaen aussehen wrde.
from kostenstellen a, bereiche b where b.kst = a.kst and b.bereich = 'VT'

Datenbankbergreifende Abfragen Bei datenbankbergreifenden Abfragen ist es ideal, wenn sich alle an der Abfrage beteiligten Tabellen in der gleichen Datenbank befinden. Bei Antwortszeitproblemen sollten Sie ber den Umzug von Tabellen nachdenken und diese anschlieend im Dialog mit Hilfe eines Synonyms und eines Datenbanklinks versorgen. Views Wenn im Ausfhrungsplan die Operation VIEW auftaucht, dann gilt nicht unbedingt Alarmstufe Rot, jedoch sollten Sie dem Ganzen einen Moment Ihrer Aufmerksamkeit widmen, denn wenn die View viele Datenstze materialisiert und mitten im Ausfhrungsplan auftaucht, dann wrde es mich nicht wundern, wenn die gesamte Abfrage nicht besonders schnell terminiert.

Tuning von Abfragen

341

Auf der anderen Seite kann es in Extremsituationen aber auch helfen, die Ausfhrung einer View durch nderung der zugrundeliegenden Definition zu erzwingen, indem Sie beispielsweise eine distinct-Klausel hinzufgen. Liefert die View nmlich sehr wenige oder sogar nur einen Datensatz, dann kann das Herauslsung und separate Ausfhren dieser Teilabfrage sogar Geschwindigkeitsvorteile bringen. Gruppierende Abfragen Vertauschen Sie bei einer gruppierenden Abfrage nicht die Bedeutung von where und having. Alle Einschrnkungen, die schon in der where-Klausel durchgefhrt werden knnen, sollten von Ihnen auch dort spezifiziert werden, d.h. in der having-Klausel sollten Sie nur diejenigen Zusatzbedingungen kodieren, die wirklich erst bei der Gruppierung geprft werden knnen. Dies mchte ich mit dem folgenden kleinen Beispiel verdeutlichen, in dem ich die Lohnartensumme fr die Lohnart 350 auswerte.
SQLWKS> select la, sum(betr07) 2> from lohnarten 3> group by la 4> having la = '350' 5> LA SUM(BETR01 --- ---------350 2000 1 row selected.

Zwar liefert diese Abfrage das richtige Ergebnis und dennoch liegt ihr eine zweifelhafte Verfahrensweise zugrunde, denn in dem Fall wrde die gesamte Tabelle ausgewertet und gruppiert und aus diesem vollstndigen Zwischenergebnis werden erst zum Schluss alle nicht bentigten Lohnarten herausgefiltert. Dabei ist es sicherlich besser, diese Schritte genau umgekehrt durchzufhren, d.h. es werden wirklich nur die bentigten Datenstze gruppiert, so dass die Abfrage folgendermaen umgestellt werden muss.
SQLWKS> select la, sum(betr07) 2> from lohnarten 3> where la = '350' 4> group by la 5> LA SUM(BETR07 --- ---------350 2000 1 row selected.

3.4.4

Verwenden von Hints

Zumindest derzeitig sind die in den Datenbanksystemen verfgbaren Abfrageoptimierer sicherlich schon sehr leistungsfhig und dennoch gibt es Situationen, in denen sich der Abfrageerfolg in Form kurzer Auswahlzeiten nicht so richtig einstel-

342

Abfragen

len will. In dem Fall haben Sie in vielen Datenbanksystemen die Mglichkeit, einen gewissen Einfluss auf die Arbeitsweise des Optimierers zu nehmen, um hierdurch zu einem anderen und in dem vorliegenden Spezialfall besseren Ausfhrungsplan zu kommen. Wenn Sie in Oracle regelbasiert optimieren, dann beschrnken sich Ihre Einflussmglichkeiten allerdings auf die Umstellung der Abfrage oder der Anlage zustzlicher Indexe. Bei der kostenbasierten Optimierung steht Ihnen neben der Anlage von Indexen und der Erstellung zustzlicher Statistiken vor allem das Werkzeug der sogenannte Hints zur Beeinflussung des Ausfhrungsplans zur Verfgung. Bei solchen Hints handelt es sich um spezielle Anweisungen, die als Kommentar getarnt in die Abfrage eingebaut werden, so dass sich das Ganze schematisch folgendermaen darstellt:
select /*+ Hint-Liste */ persnr, lfdnr, ... from

In jeder Abfrage knnen sie mittels der Begrenzungszeichen /* und */ Kommentare einfgen, wobei diesmal das zustzlich verwendete Pluszeichen (+) auf mgliche Hint-Kommandos hinweist. Ich bekomme hierbei stark den Eindruck, dass diese Schreibweise aus einer Not heraus geboren wurde, denn fr die Verwendung irgendwelcher Optimierhinweise gibt es zum einen natrlich keine Normierung und zum anderen wollte man seitens von Oracle sicherlich nicht das Format der einzelnen Abfragen auf den Kopf stellen, nur um spezielle Ausfhrungskennzeichen verarbeiten zu knnen. Das Problem bei den Hints bzw. dem Verstecken in einem Kommentar ist nmlich, dass Oracle fehlerhaft geschriebene Krzel einfach als Kommentar betrachtet, d.h. es erfolgt weder die nderung des Ausfhrungsplans, noch die Ausgabe einer Fehlermeldung.
select /*+ Lidel ist billig aber Aldi ist billiger*/ persnr, ... from

Dieser sinnlose und nicht bekannte Hint ist in Wirklichkeit nur ein Kommentar, der auf den ersten Blick nur wie ein Hint aussieht. In der nachfolgende Tabelle (vgl. 3.11) finden Sie eine bersicht einiger wichtiger Hints, wobei Sie die vollstndige Liste aller verfgbaren Kommandos in der Dokumentation im Buch Oracle8 Tuning und dort im Kaptitel Optimization Modes and Hints finden.
Hint rule Beschreibung Dieser Hint fhrt zur regelbasierten Optimierung fr eine spezielle Abfrage. Gerade wenn sich nach einer Umstellung des Optimierungsmodus fr die eine oder andere Abfrage Laufzeitprobleme einstellen, dann knnen Sie darauf mit dem Hint schnell reagieren, in dem Sie die zugehrigen Abfragen immer noch regelbasiert ausfhren.

Tuning von Abfragen

343

Hint ordered

Beschreibung Bei der regelbasierten Optimierung haben Sie gelernt, dass die Tabellen in Abhngigkeit der from-Klausel ausgewertet werden. Der ordered-Hint fhrt bei der kostenbasierten Optimierung zu einer hnlichen Verfahrensweise, wobei die Tabellen diesmal von links nach rechts bzw. oben nach unten ausgewertet werden. fhrt zu einem FULL TABLE SCAN fr die vorgegebene Tabelle mit dem Alialsnamen a. erzwingt die Verknpfung der Tabellen a und b unter Verwendung der entsprechenden Join-Operation, beispielsweise fhrt use_nl zur Anwendung eines NESTED LOOPS . Umformung einer not in-Unterabfrage in einen Hash- bzw. Merge-AntiJoin. empfiehlt die Verwendung eines Index fr die Tabelle mit dem Aliasnamen a. Statt eines speziellen Indexnames knnen Sie hierbei auch mehrere Indices vorschlagen. entspricht dem Index-Hint, wobei der Index jetzt absteigend durchlaufen werden soll.

full(a) use_nl(a b), use_merge(a b), use_hash(a b) hash_aj, merge_aj index(a Index)

index_desc

Tabelle 3.11: bersicht einiger ausgewhlter Hints

Beispiele Damit bleibt eigentlich nur noch die Frage offen, wie diese Hints genau innerhalb einer Abfrage verwendet werden, was ich zum Abschluss dieses Kapitels anhand einiger Beispiele demonstrieren will. Beginnen wir dabei mit dem Hint index, der dem System die Verwendung desselben nahe legt.
select /*+ index(a personalien1)*/ * from personalien a where name like 'R%'; LEVEL POSITION Q_PLAN ---------- ---------- ---------------------------------------------1 2 SELECT STATEMENT 2 1 TABLE ACCESS BY INDEX ROWID PERSONALIEN 3 1 INDEX RANGE SCAN PERSONALIEN1
Listing 3.38: Anwendung des Index-Hints

Ohne unseren Hint wrde das System aufgrund der Gre unserer Tabelle einfach die gesamte Tabelle lesen, was sicherlich auch sinnvoll ist. Bei entsprechend groen Tabellen wird der Optimierer die passenden Indices in der Regel ganz von alleine finden, wodurch wir wieder bei einem mit der Hint-Verwendung verbundenen Problem wren. Warum soll man dem System etwas beibringen, was es bei dem Vorliegen der entsprechenden Rahmenbedingungen von ganz alleine tut? Das nchste Beispiel zeigt, wie Sie mit Hilfe eines entsprechenden Hints die Verknpfung zweiter Tabelle ber die nested loops-Mehtode erzwingen knnen.

344

Abfragen

select /*+ use_nl(a b) */ a.* from personalien a, bvs b where b.persnr = a.persnr; LEVEL POSITION Q_PLAN ---------- ---------- -----------------------------1 25 SELECT STATEMENT 2 1 NESTED LOOPS 3 1 TABLE ACCESS FULL PERSONALIEN 3 2 INDEX RANGE SCAN BVS_PK
Listing 3.39: Verwenden des use_nl-Hints

Die anderen Verknpfungs-Hints werden ganz entsprechend angewendet. Besonders einfach ist natrlich die Verwendung der Hints rule oder ordered, die ganz ohne zustzliche Parameter angewendet werden. Das nchste Beispiel dieser Thematik zeigt Ihnen einmal die gleichzeitige Verwendung verschiedener Hints (vgl. Listing 3.40). Dabei erstellen wir wieder eine Abfrage, in der wie die Personalien, Beschftigungsverhltnisse und die Gehlter miteinander verknpfen. Die ersten beiden Tabellen sollten dabei ber die Methode nested loops und die Gehaltstabelle mit Hilfe eines merge joins verknpft werden.
select /*+ ordered use_nl(a b) use_merge(c) */ a.* from personalien a, bvs b, gehalt c where b.persnr = a.persnr and c.persnr = b.persnr and c.lfdnr = b.lfdnr; LEVEL POSITION Q_PLAN ---------- ---------- ---------------------------------------1 33 SELECT STATEMENT 2 1 MERGE JOIN 3 1 SORT JOIN 4 1 NESTED LOOPS 5 1 TABLE ACCESS FULL PERSONALIEN 5 2 INDEX RANGE SCAN BVS_PK 3 2 SORT JOIN 4 1 TABLE ACCESS FULL GEHALT
Listing 3.40: Anwenden einer ganzen Hintliste

Wie Sie dem im Listing 3.40 gezeigten Ausfhrungsplan entnehmen knnen, werden die Gehaltstabelle und das Ergebnis der Verknpfung zwischen Personalien und Beschftigungsverhltnis in der Tat mit Hilfe eines Merge-Joins verknpft, weshalb Sie auch jedes Mal vorher die Operation SORT JOIN im Ausfhrungsplan finden. Die anderen beiden Tabellen werden ber einen NESTED LOOPS miteinander verbunden.

Tuning von Abfragen

345

Damit das Ganze auch wirklich so wie in der Hint-Liste vorgegeben funktioniert, muss Oracle unsere Tabellen wie in der from-Klausel vorgegeben abarbeiten, weshalb wir zustzlich auch den ordered-Hint spezifizieren mssen. Damit kommen wir zum letzten Beispiel, indem wir uns einmal die Verwendung von Hints innerhalb einer Unterabfrage anschauen. Im Prinzip knnen Sie pro Abfrage eine Hintliste spezifizieren, d.h. die verschiedenen Unterabfragen knnen eigene Hints enthalten. Wir schauen uns das anhand der schon hufig strapazierten Gehaltsabfrage an, wo wir mit Hilfe einer Unterabfrage den letzten Gehaltsdatensatz ermitteln (vgl. Listing 3.41).
select /*+ index(c geh_dat) */ c.* from gehalt c where c.gab = (select /*+ use_merge(b c1) */ max(gab) from gehalt c1, bvs b where c1.persnr = c.persnr and c1.lfdnr = c.lfdnr and b.persnr = c1.persnr and b.lfdnr = c1.lfdnr); LEVEL POSITION Q_PLAN ---------- ---------- --------------------------------------1 2 SELECT STATEMENT 2 1 FILTER 3 1 TABLE ACCESS BY INDEX ROWID GEHALT 4 1 INDEX FULL SCAN GEH_DAT 3 2 SORT AGGREGATE 4 1 MERGE JOIN 5 1 INDEX UNIQUE SCAN BVS_PK 5 2 FILTER 6 1 TABLE ACCESS FULL GEHALT
Listing 3.41: Anwenden zustzlicher Hints in einer Unterabfrage

Machen Sie die Gegenprobe und Sie werden feststellen, dass der Ausfhrungsplan ohne die Vorgabe der Hints ganz anders aussieht. Die Tabellen der Unterabfrage werden dann ber die Methode NESTED LOOPS verbunden und der Zugriff auf die Gehaltstabelle erfolgt ohne die Verwendung eines Index. Zusammenfassung Man kann es nicht oft genug sagen, aber ich halte die Verwendung von Hints nur in Ausnahmefllen fr gerechtfertigt, auch wenn das Experimentieren mit diesen Kommandos durchaus Spa machen kann. Wenn Sie schon bei der Entwicklung von Abfragen Hints einsetzen, dann haben Sie das Problem, dass Sie eigentlich nicht wissen, ob die Datenbank in der Produktionsumgebung nicht ganz von alleine auf den gleichen oder sogar bessere Ausfhrungsplne kommt. Zum anderen kann es passieren, dass der Optimierer nach dem Einspielen des neusten Patches eine bestimmte Abfrage anders bzw. besser analysiert, d.h. durch die Verwendung von Hints berauben Sie sich dieser Option. Bei der Verwendung von Hints ist also ein gewisses Fingerspitzengefhl gefragt.

346

Abfragen

Auerdem sollte man den Ausfhrungsplan nach dem Einfgen zustzlicher Hints kontrollieren, da es bei der Ausfhrung der Abfrage niemals Fehlermeldungen wegen fehlerhafter Hints gibt. Wird der Optimierbefehl nicht im Ausfhrungsplan sichtbar, dann kann das folgende Grnde haben:

: : :

Der Hint ist falsch kodiert, enthlt fehlerhafte Parameter oder wurde fehlerhaft geschrieben. Es handelt sich (z.B. index) um einen Vorschlagshint, die vorgegebenen Optionen machen aber alle keinen Sinn und werden deshalb ignoriert. Der Hint wird durch einen bergeordneten Befehl auer Kraft gesetzt oder macht in der verwendeten Kombination keinen Sinn.

3.5

Data Dictionary Views

Der letzte Teil des Kapitels ber die Abfragen fhrt uns zu einem Streifzug durch die vom System bereitgestellten Views zur Abfrage verschiedenster Informationen aus dem Data Dictionary. Mit Hilfe dieser Views knnen Sie Informationen ber die in der Datenbank gespeicherten Objekte, den Zugriffsrechten einzelner Benutzer oder aktuelle Datenbankaktivitten sammeln. Im Prinzip knnte ich mit diesem letzten Abschnitt das gesamte Buch voll machen, denn die Liste der verfgbaren Views ist so lang, dass die Beschreibung jeder einzelnen View, womglich noch zusammen mit einem kleinen Anwendungsbeispiel, den gesetzten Rahmen bei weitem sprengen wrde. Aus dem Grund werde ich mich auf einige ausgewhlte Beispiele beschrnken und verweise ansonsten einmal wieder auf die zugehrigen Passagen der OracleDokumentation. Konkret finden Sie eine vollstndige bersicht und Beschreibung aller verfgbaren Data Dicitionary Views im Buch Oracle8 Reference. Beim erstmaligen berfliegen der vorhandenen Views fllt zunchst einmal auf, dass verschiedene dieser Sichten hnliche Namen aufweisen und sich eigentlich nur durch die Prfixe all, dba und user unterscheiden. In der Tat liefern die entsprechenden Views (z.B. all_tables, dba_tables und user_tables) ganz hnliche Ergebnisse und unterscheiden sich zum einen nur durch die Menge der selektierten Datenstze und zum anderen durch die standardmig installierten Zugriffsrechte auf diese Objekte, d.h. beispielsweise hat jeder Benutzer normalerweise Zugriff auf die user-Views aber nicht automatisch Zugriff auf die dba-Views. In der Tabelle 3.12 finden Sie eine bersicht, was die einzelnen Prfixe gewhnlich in Bezug auf die Selektion bewirken.
Prfix user all dba Beschreibung fhrt zur Anzeige aller im eigenen Schema enthaltenden Objekte. enthlt alle Objekte der entsprechender user-View plus alle Objekte auf die der aktuelle Benutzer Zugriff hat. enthlt alle in der Datenbank vorhandenen Objekte.

Tabelle 3.12: Bedeutung der Prfixe bei den unterschiedlichen Systemviews

Data Dictionary Views

347

Bevor es nun losgeht, noch ein Hinweis in eigener Sache: Bei dem Arbeiten mit den verschiedenen Views gehe ich im Folgenden nicht auf die Bedeutung der einzelnen gelieferten Spalten ein, denn wie schon gesagt, finden Sie eine ausfhrliche Beschreibung jeder vorhandenen Systemview in der Oracle-Dokumentation.

3.5.1

Analyse der Datenbankobjekte

Im ersten Schritt mchte ich die Verwendung verschiedener Views demonstrieren, mit deren Hilfe Sie Informationen ber die in der Datenbank gespeicherten Objekte erhalten knnen. Die meisten Abfragen erstelle ich dabei anhand der userViews, wobei Sie natrlich genauso gut eine der anderen Viewkategorieen verwenden knnen. Eventuell mssen Sie dabei nur bercksichtigen, neben dem Objektnamen auch noch den Namen des zugehrigen Schemas zu spezifizieren. Informationen ber Tabellen Informationen ber die in der Datenbank vorhandenen Tabellen erhalten Sie in erster Linie durch Abfrage der View user_tables. Neben verschiedenen Informationen zu dem verwendeten Tablespace oder der Speicherbelegung finden Sie hier auch einen Eintrag, ob bzw. wann fr die Tabelle zuletzt eine Statistik erstellt wurde. Neben den Informationen zu einer einzelnen Tabelle knnen Sie mit Hilfe dieser bzw. der entsprechenden dba-View aber auch ganz gut feststellen, welche Tabellen alle in einem speziellen Tablespace gespeichert sind.
SQLWKS> select table_name 2> from user_tables 3> where tablespace_name = 'USR'; TABLE_NAME -----------------------------AUSTRITTSGRUENDE BLAENDER BVS GEHALT KOSTENSTELLE ... 12 rows selected.
Listing 3.42: Verwendung der View user_tables zur Analyse der Tablespacebelegung

Analyse der Tabellenstruktur Informationen ber den konkreten Aufbau einer Tabelle erhalten Sie mit Hilfe der View user_tab_columns. Mit Hilfe einer entsprechenden Abfrage knnen Sie beispielsweise leicht feststellen, welche Tabellen alle das Feld persnr enthalten.
SQLWKS> select table_name 2> from user_tab_columns 3> where column_name = 'PERSNR';

348

Abfragen

TABLE_NAME -----------------------------AKTUELLES_GEHALT BVS GEHALT LOHNARTEN PERSONALIEN 5 rows selected.


Listing 3.43: Ermittlung der Verwendung eines bestimmten Feldes mit Hilfe der View user_tab_columns

Auerdem verwende ich diese View gerne, um innerhalb von Programmen dynamische SQL-Anweisungen zu erzeugen. Auch hierzu mchte ich ein kleines Beispiel vorstellen und eine Funktion erstellen, mit deren Hilfe Sie eine Zeichenfolge mit allen in der Tabelle vorhandenen Spalten erstellen knnen, um diese beispielsweise in einer select oder insert into-Anweisung zu verwenden.
create or replace function get_fieldlist(in_table in varchar2) return varchar2 is out_liste varchar2(5000); begin declare cursor get_cols is select column_name, data_type from user_tab_columns where table_name = in_table order by column_id; col_record get_cols%rowtype; begin open get_cols; out_liste := ' '; loop fetch get_cols into col_record; exit when get_cols%notfound; out_liste := out_liste || ', ' || col_record.column_name; end loop; close get_cols; return substr(out_liste, 4); end; end;
Listing 3.44: Erstellen einer Feldliste fr eine beliebige Datenbanktabelle

Data Dictionary Views

349

Innerhalb der selbsterstellten Funktion get_fieldlist ermitteln wir mit Hilfe des Cursors get_cols und der zugehrigen Abfrage auf die View user_tab_columns die Spalten der beim Funktionsaufruf bergebenen Tabelle. Beim Verarbeiten der vom Cursor gelieferten Datenstze hngen wir die einzelnen Feldnamen mit Hilfe der Ausgabevariable out_liste aneinander. Neben den Feldnamen und der in der Tabelle verwendeten Reihenfolge liefert die View natrlich auch weitere Informationen wie den Datentyp oder die null/not null-Einstellung des Feldes. Das folgende Beispiel (vgl. Listing 3.45) zeigt Ihnen die Verwendung unserer neuen Funktion get_fieldlist zur Erstellung einer Feldliste fr eine beliebige Tabelle.
SQLWKS> select get_fieldlist('PERSONALIEN') from dual 2> GET_FIELDLIST('PERSONALIEN') -------------------------------------------------------------------------------PERSNR, NAME, STRASSE1, STRASSE2, STRASSE3, STRASSE4, ORT, LAND, BLAND, PLZ, TEL 1 row selected.
Listing 3.45: Verwenden der Funktion get_fieldlist

Analyse von Indices Neben den Tabellen knnen Sie mit Hilfe der Systemviews natrlich auch nach Indices bzw. deren Aufbau forschen. Hierbei ist zunchst einmal die View user_indexes zu nennen, mit deren Hilfe Sie beispielsweise die zu einer Tabelle gehrenden oder in einem Tablespace gespeicherten Indices ermitteln knnen.
SQLWKS> select index_name, tablespace_name 2> from user_indexes 3> where table_name = 'GEHALT'; INDEX_NAME TABLESPACE_NAME ------------------------------ -----------------------------GEHALT_PK INDX 1 row selected.
Listing 3.46: Ermitteln der fr eine Tabelle vorhandenen Indices

Analog zu den user_tab_columns existiert auch fr die Indices eine weitere View mit dem Namen user_ind_columns, mit deren Hilfe Sie die Struktur jedes beliebigen Index ermitteln knnen. In unserem Beispiel erhalten Sie hierbei fr den Index GEHALT_PK folgendes Ergebnis (vgl. Listing 3.47).
SQLWKS> 2> 3> 4> 5> select column_name from user_ind_columns where index_name = 'GEHALT_PK' and table_name = 'GEHALT' order by column_position;

350

Abfragen

COLUMN_NAME -------------------------------------------------------------PERSNR LFDNR GAB 3 rows selected.


Listing 3.47: Ermittlung des Aufbaus des Primrschlssels der Gehaltstabelle

Aufbau einer View ermitteln Eigentlich soll der Zugriff auf Daten und Zusammenhnge mit Hilfe einer View abstrahiert werden und dennoch ist es manchmal notwendig, die sich hinter einer View verbergende Auswahlabfrage anzuzeigen, beispielsweise um die aktuelle Version des Abfrageobjekts zu berprfen oder sogar um die in der View abstrahierten Zusammenhnge nachzuvollziehen. Hierzu stellt Oracle Ihnen die Systemview user_views zur Verfgung, mit deren Hilfe Sie Zugriff auf die in der View gespeicherten Abfrage haben (vgl. Listing 3.48).
SQLWKS> set longwidth 1000; Longwidth 1000 SQLWKS> select text_length, text 2> from user_views 3> where view_name = 'AKTUELLES_GEHALT' 4> TEXT_LENGT TEXT ---------- -----------------------------------------297 select a.persnr, b.lfdnr, a.name, b.kst from personalien a, gehalt b where b.persnr = a.persnr and b.gab = (select max(gab) from gehalt b1 where b1.persnr = b.persnr and b1.lfdnr = b.lfdnr and b1.gab <= sysdate ) 1 row selected.
Listing 3.48: Analyse der einer View zugrundeliegenden Abfrage

Beachten Sie bei diesem Beispiel die erste Anweisung, mit deren Hilfe die Ausgabe bzw. Formatierung von Textfeldern (Datentyp long) verndert wurde. Damit der in diesem Datenfeld gespeicherte Text nicht nach einigen Zeichen abgeschnitten wird, mssen Sie den Ausgabebereich entsprechend erhhen. Die View selbst liefert Ihnen im Zweifelsfall brigens die bentigte Textlnge, indem Sie hierzu das Feld text_length abfragen.

Data Dictionary Views

351

Vorhandene Trigger analysieren Mit Hilfe der View user_triggers erhalten Sie einen berblick ber die in Ihrem Schema bzw. der Datenbank installierten Trigger. Neben dem im Feld trigger_body gespeicherten PL/SQL-Programm erhalten Sie hierdurch unter anderem auch Informationen ber die zugehrige Tabelle oder den installierten Aufrufmechanismus. Da es sich bei dem Feld trigger_body wieder um ein Textfeld vom Datentyp long handelt, mssen Sie eventuell die Textausgabe wieder mit Hilfe des Parameters longwidth geeignet einstellen.
SQLWKS> select trigger_body 2> from dba_triggers 3> where trigger_name = 'LOHNARTEN_UPD' 4> TRIGGER_BODY -----------------------------------------------------------begin if to_char(sysdate,'D') not in ('5','7') then raise_application_error(-20001,'Die Tabelle kann nur am Wochenende gendert werden.'); end if; end; 1 row selected.
Listing 3.49: Analyse eines Triggerprogramms

Funktionen, Prozeduren und Pakete durchleuchten Informationen ber die in der Datenbank bzw. Ihrem Schema gespeicherten Funktionen, Prozeduren oder Pakete erhalten Sie mit Hilfe der View user_source. Im Unterschied zu den letzten beiden Beispielen werden die Programmteile dieser Objekte allerdings nicht in einem Textfeld, sondern entsprechend der Eingabe zeilenweise gespeichert, weshalb Sie im Feld line die Ausgabe einer laufenden Nummer finden. ber die Spalte type erhalten Sie Informationen ber den Typ des gespeicherten Objekts. Die mglichen Werte entsprechend den verfgbaren Objekten, d.h. die Spalte liefert die nachfolgenden Ergebnisse:
SQLWKS> select distinct type from dba_source; TYPE -----------FUNCTION PACKAGE PACKAGE BODY PROCEDURE TYPE 5 rows selected.

Das nun folgende Beispiel (vgl. Listing 3.50) erstellt ein Listing der soeben erstellten Funktion zur Auswertung unserer Tabellenstruktur.

352

Abfragen

select rtrim(text) from user_source where name = 'GET_FIELDLIST' order by line;


Listing 3.50: Erstellen eines Listings fr eine selbsterstellte Funktion

Gerade im Zusammenhang mit Funktionen oder Prozeduren ist manchmal auch interessant, welche Argumente diese Objekte beim Aufruf erwarten, weshalb Sie auch diese Informationen mit Hilfe einer entsprechenden View abfragen knnen. Die heit konkret user_arguments und im nchsten Listing (vgl. 3.51) finden Sie wieder ein Beispiel fr ihren Gebrauch.
SQLWKS> select argument_name, position, data_type, in_out 2> from user_arguments 3> where object_name = 'GET_FIELDLIST'; ARGUMENT_NAME POSITION ------------------------------ ---------0 IN_TABLE 1 2 rows selected. DATA_TYPE -------------VARCHAR2 VARCHAR2 IN_OUT --------OUT IN

Listing 3.51: Abfrage der Argumentstruktur fr eine selbsterstellte Funktion

3.5.2

Aktivitten in der Datenbank abfragen

Die meisten der zu dieser Kategorie passenden Systemviews beginnen mit dem Prfix v$, d.h. diesmal findet in den meisten Fllen keine Unterscheidung nach Schemazugehrigkeit oder Zugriffsrechten statt. Datenbank abfragen Beginnen mchten ich hierbei mit einem ganz einfachen Beispiel. Sofern Sie in einem Skript oder einem Programm berprfen mchten, in welcher Datenbank Sie sich gerade befinden, dann knnen Sie das mit Hilfe einer Abfrage der View v$database durchfhren (vgl. Listing 3.52).
SQLWKS> select dbid, name, created 2> from v$database 3> DBID NAME CREATED ---------- --------- -------------------3206369407 DATENB01 31-JUL-00 1 row selected.
Listing 3.52: Abfrage des Datenbanknamens

Data Dictionary Views

353

Datenbankparameter ermitteln Eine beliebte Frage jeder Hotline ist immer die nach den aktuellen Werten verschiedener Datenbankparameter und da der Zugriff auf die Initialisierungsdatei der Datenbankinstanz nicht unbedingt immer gegeben ist, knnen Sie die aktuellen Parametereinstellungen auch per Abfrage auf die View v$parameter ermitteln. Mit Hilfe des nachfolgenden Beispiels (vgl. Listing 3.53) wird die aktuelle Arbeitseinstellung des Optimierers abgefragt.
SQLWKS> select name, value 2> from v$parameter 3> where name = 'optimizer_mode'; NAME VALUE -------------------------------------------------- -----------------optimizer_mode CHOOSE 1 row selected.
Listing 3.53: Abfrage von Parametereinstellungen mit Hilfe der View v$parameter

Aktive Sessions ermitteln Mit Hilfe der View v$sessions knnen Sie alle aktive Sitzungen bzw. die Anmeldungen eines bestimmten Benutzers abfragen. Das folgende Beispiel (vgl. Listing 3.54) zeigt Ihnen von den insgesamt verfgbaren Spalten ein paar ausgewhlte Felder, die vor allem fr weitergehende Forschungen interessant sein knnen.
SQLWKS> select sid, serial#, sql_address, command, status, 2> osuser, terminal 3> from v$session 4> where username = 'UBEISPIEL'; 5> SID SERIAL# SQL_ADDR COMMAND STATUS OSUSER TERMINAL ----- ---------- -------- ---------- -------- --------------- --------9 18 0213E4E0 0 ACTIVE Administrator RAY_DELL 1 row selected.
Listing 3.54: Abfrage der aktiven Sitzungen des Benutzers UBEISPIEL

Beispielsweise bentigen Sie die Felder sid und serial#, um eine hngende Session aus dem System zu entfernen, d.h. wenn nichts mehr geht, dann besteht die erste Aktion darin, die zugehrige Session zu finden und die Werte dieser beiden Felder zu ermitteln. Anschlieend knnen Sie die aus dem System herausschmeien, indem Sie einen entsprechenden alter system-Befehl absetzen.
alter system kill session '9,18';

Dieser Befehl bentigt als Parameter eine Zeichenfolge, in der die beiden Werte sid und serial# durch Komma getrennt enthalten sind, d.h. in meinem Beispiel knnte ich meine Session durch das eben gezeigte Beispiel abschieen, wobei die Anwendung dieser Schiebung den Datenbankadministratoren vorbehalten ist.

354

Abfragen

Manchmal ist es nicht ganz so einfach, bei Problemen die zugehrige Session zu ermitteln, was vor allem dann gilt, wenn sich die einzelnen Benutzer nicht direkt sondern stattdessen alle mit der gleichen Benutzer-Id anmelden, wobei diese zentrale Anmeldung vielleicht sogar noch ber einen speziellen Anwendungsserver erfolgt. In solchen Fllen kann Ihnen vielleicht die Spalte command weiterhelfen, mit deren Hilfe die momentane Aktivitt der Sitzung verschlsselt wird. Eine vollstndige bersicht der mglichen Schlssel finden Sie in der Oracle-Dokumentation hinter der Beschreibung v$session-View, d.h. ich habe Ihnen in der Tabelle 3.13 nur die wichtigsten Schlssel zusammengestellt.
Command 0 2 3 6 7 Beschreibung Es wird gerade kein Befehl ausgefhrt. insert-Anweisung. Ausfhrung einer Auswahlabfrage. update-Anweisung. delete-Anweisung.

Tabelle 3.13: Ausgewhlte Verschlsselungen der command-Spalte der View v$session

Wenn auch das nicht weiterhilft, dann haben Sie auch noch die Mglichkeit herauszufinden, welche Aktivitten die einzelnen Sitzungen im Detail gerade durchfhren. Hierzu knnen Sie beispielsweise die aktuellen Sperrungen oder das gerade ausgefhrte SQL-Kommando mit Hilfe weiterer Systemviews auslesen. Mehr dazu erfahren Sie in den folgenden Abschnitten. Sperrungen ermitteln Die in einer Session durchgefhrten Sperrungen knnen Sie mit Hilfe der Views v$lock bzw. v$locked_object ermitteln. In beiden Fllen knnen Sie mit der SessionId (sid) in die Abfrage einsteigen, wobei die zweite der genannten Views die einfachere Verbindung zur zugehrigen Tabelle ermglicht, d.h. bei Sperrkollisionen ist der Einstieg ber v$locked_object meistens einfacher. Um das nachfolgende Beispiel auszuprobieren bentigen Sie wieder zwei Sitzungen Ihres SQL-Editors. Verwenden Sie eine der beiden Sitzungen, um mit Hilfe einer Auswahlabfrage einen oder mehrere Datenstze zu sperren.
select * from personalien where persnr = '7000188' for update;

Mit Hilfe der zweiten Sitzung wollen wir nun die in der Datenbank gesperrten Objekte ermitteln, was mit folgender Abfrage (vgl. Listing 3.55) mglich wre.
SQLWKS> select a.session_id, a.oracle_username, a.os_user_name, b.object_name 2> from v$locked_object a, 3> user_objects b 4> where b.object_id = a.object_id;

Data Dictionary Views

355

SESSION_ID ORACLE_USERNAME OS_USER_NAME OBJECT_NAME ---------- ------------------------------ --------------- -----------9 UBEISPIEL Administrator PERSONALIEN 1 row selected.
Listing 3.55: Abfrage aktueller Sperrungen

Wie Sie der Abfrage entnehmen knnen, ermitteln wir mit Hilfe der Objekt-Id den Namen des gesperrten Objekts, indem wir die Id mit Hilfe der View user_objects auflsen. Ist diese Sperrung beispielsweise seit lngerem in der Datenbank und fhrt zur Behinderung andere Aktivitten, dann knnten Sie jetzt in einem zweiten Schritt mit Hilfe einer weiteren Abfrage auf die View v$session den zugehrigen Wert fr das Feld serial# ermitteln und wren damit in der Lage, den Sitzungsabbruch in der oben beschriebenen Weise zu erzwingen, wodurch auch die Sperrungen aufgehoben wrden. Aktivitt der Sitzung aufstbern Nicht nur bei langlaufenden Skripten oder Programmen stellt sich manchmal die Frage, was im Rahmen einer Datenbanksitzung gerade so angestellt wird. Auch das kann man mit Hilfe der vorhandenen Systemviews ermitteln, wenn man zunchst einmal die zugehrige Sitzungs-Id festgestellt hat. Die View v$session liefern nmlich mit ihrem Wert sql_address die Mglichkeit, gezielt in eine weitere View mit dem Namen v$sql einzusteigen, mit deren Hilfe Sie das aktuell in der SGA befindliche SQL-Statement abfragen knnen. Auf meinem Rechner werden die Personalien immer noch durch die oben abgesetzte Abfrage gesperrt, d.h. die zugehrige Abfrage sollte sich noch in der SGA befinden, was im Folgenden (vlg. Listing 3.56) geprft bzw. festgestellt wird.
SQLWKS> select a.sql_text 2> from v$sql a, 3> v$session b 4> where b.sql_address = a.address 5> and b.sid = 9; SQL_TEXT ---------------------------------------------------------------------select * from personalien where persnr = '7000188' for update 1 row selected.
Listing 3.56: Ermittlung des aktuell von der Sitzung ausgefhrten SQL-Kommandos

3.5.3

Zugriffsrechte entschlsseln

Auch zur Auswertung der in der Datenbank vorhandenen Benutzer, Rollen und deren zugewiesenen Einzelrechten finden Sie in Ihrer Oracle-Datenbank eine Reihe von Systemviews. Ebenso wie bei den Datenbankobjekten, existieren auch hierbei

356

Abfragen

wieder eine Reihe von hnlichen Views mit den unterschiedlichen Prfixen all, dba und user, die genau wie damals bei der Analyse der verschiedenen Datenbankobjekte eine voreingestellte Sicht auf die insgesamt verfgbaren Sicherheitsinformationen liefern. So liefert beispielsweise die View user_tab_privs wieder die auf einzelnen Tabellen vergebenen Rechte fr den aktuellen Benutzer, wohingegen Sie mit Hilfe der View dba_tab_privs diese Rechte fr jeden beliebigen Benutzer abfragen knnen. Wenn Sie an dieser Stelle allerdings nun wieder das eine oder andere Beispiel erwarten, dann muss ich Sie auf das nchste Kapitel vertrsten, indem die ganze Thematik der Benutzer und Rollen behandelt wird. Ich finde, dass die Beispiele dort besser aufgehoben sind, so dass ich mich hier lediglich fr eine Aufstellung (vgl. Tabelle 3.14) der wichtigsten Views entschieden habe. Bei der Erstellen dieser Liste habe ich mich auf die Aufzhlung der dba-Views beschrnkt, die entsprechend meiner eben gemachten Erklrung ebenfalls als all- und user-Variante vorliegen.
View dba_users dba_roles dba_sys_privs dba_tab_privs dba_col_privs dba_role_privs role_role_privs role_tab_privs Beschreibung liefert eine Liste der im System definierten Benutzer. listet analog zu dba_users die vorhandenen Rollen auf. zeigt die einem Benutzer bzw. einer Rolle verliehenen System-Privilegien (z.B. create table) an. liefert die vergebenen Zugriffsrechte fr ganze Tabellen. Hierdurch erhalten Sie ggf. die Zugriffsrechte fr einzelne Spalten. zeigt die dem Benutzer zugewiesenen Rollen an. liefert die einer Rolle zugewiesenen Rollen. listet die mit einer Rolle verknpften Zugriffsrechte auf Tabellen auf.

Tabelle 3.14: Ausgewhlte Systemviews zur Auswertung von Benuzterprofilen und Rollen

Benutzer und Rollen

Mit Hilfe des vierten Kapitel werden wir uns im Folgenden ein wenig mit der in Datenbanken blichen Benutzerverwaltung beschftigen und uns dabei anschauen, was Oracle Ihnen hierbei als Untersttzung zu bieten hat. Um es gleich vorweg zu nehmen: die zu diesem Thema gehrenden Mglichkeiten stecken zumindest im Vergleich zu den sonstigen Funktionalitten noch in den Kinderschuhen. Das ist allerdings kein spezifischer Makel der Oracle-Datenbank, sondern in Bezug auf diesen Punkt knnen sich eigentlich alle derzeitig aktiven Hersteller die Hand geben. Vielleicht liegt das allerdings auch daran, dass wir im Bereich der Zugriffsrechte fr einzelne Benutzer, die wir am liebsten benutzerindividuell auf Datensatz und Feldebene vergeben wrden, ein wenig bereifrig sind, denn eine gewisse Grundfunktionalitt ist in den heute verfgbaren Datenbanksystemen schon vorhanden, nur uns scheint das niemals zu reichen. Damit Sie mich nicht falsch verstehen: Sicherlich ist es notwendig, die in einer Datenbank gespeicherten Informationen vor dem Missbrauch durch Dritte zu schtzen. Was in deutschen Unternehmen allerdings zum Teil getrieben wird, das kann schon ziemlich abenteuerlich sein, wenn auf Feldebene, also auch in Abhngigkeit spezieller Feldinhalte, unterschiedliche Rechte im Bezug auf das Lesen, ndern, Einfgen und Lschen von Datenstzen bzw. einzelner Felder gefordert werden.

4.1

Einfhrung in die Benutzerverwaltung

Ausgangspunkt bei der Arbeit mit einem Datenbanksystem ist der einzelne Benutzer oder User mit seinem in der Datenbank gespeicherten Profil. Einem solchen Benutzer entspricht in der Realitt blicherweise ein konkreter Anwender, wobei es im Regelfall auch eine Reihe von technischen Benutzern gibt (z.B. sys oder system), die zur Administrierung der Datenbank verwendet werden. Ein solcher Benutzer besitzt vor allem eine in der Datenbank eindeutige Kennung, die sogenannte Benutzer- bzw. User-Id und blicherweise ein nur ihm bekannte Passwort, wobei diese beiden Informationen beim Anmelden an die Datenbank bentigt werden. Daneben steht der Benutzer auch noch fr eine Sammlung von zugewiesenen Berechtigungen, die im Einzelnen regeln, welche Datenbankobjekte der Benutzer verwenden oder welche sonstigen Aktivitten er in der Datenbank ausfhren darf. Die einem Benutzer zugewiesenen Berechtigungen kann man in folgende Kategorien unterteilen:

358

Benutzer und Rollen

: : :

objektbezogene Rechte Systemrechte Profile.

Objektbezogene Rechte Wie Sie in den vorherigen Kapiteln gesehen haben, zeichnet sich eine Datenbank blicherweise durch eine Vielzahl unterschiedlicher Objekte aus, die im Regelfall zusammen bzw. unter der Hoheit eines technischen Users angelegt werden. Standardmig haben alle Benutzer lediglich Zugriff auf die im eigenen Schema gespeicherten Datenbankobjekte, so dass der Zugriff auf andere Objekte wie Tabellen oder Funktionen explizit gewhrt werden muss. Systemrechte Eigentlich ist ein Benutzer bzw. Anwender jemand, der seine Tagesarbeit mit denen in einer Datenbank vorhandenen Objekte erledigt. Hierbei werden die in den Tabellen gespeicherten Daten abgefragt oder gendert oder es werden in der Datenbank gespeicherte Programme ausgefhrt. Dabei gehrt die Anlage neuer Tabellen, das Erstellen oder Lschen von Indices oder das ndern von Prozeduren oder Paketen nicht zum Aufgabengebiet eines gewhnlichen Endanwenders. Aus diesem Grund beinhaltet das Recht, eine Tabelle zu lesen oder eine Prozedur zu starten, noch lange nicht die Mglichkeit, die Struktur der Tabelle zu ndern oder das in der Prozedur gespeicherte Programm zu verbessern. Um das tun zu drfen, bentigt man weitere besondere Privilegien, die man insgesamt als Systemrechte bezeichnen kann. Zu diesen Systemrechten gehren auch weitergehende besondere Privilegien, wie zum Beispiel das Recht zur Anlage neuer Benutzer oder die Berechtigung zur Durchfhrung einer Datensicherung. Profile Eine sogenanntes Profil spielt bei der gesamten Benutzerdefinition nur eine untergeordnete Rolle. Es gibt viele Installationen, bei denen alle angelegten Benutzer das standardmig vorhandene Profil default besitzen und wo auch keine weiteren Profile in der Datenbank gespeichert sind. Ein solches Profil kann beispielsweise Limitierungen in Bezug auf die beanspruchbaren Ressourcen beinhalten, indem dort vielleicht die Gre des privaten SGABereichs oder die Anzahl der vom Benutzer parallel zu betreibenden Datenbanksitzungen vorgegeben werden. Auf der anderen Seite regelt ein solches Profil auch den Komplex der Passwortverwaltung, indem Sie dort beispielsweise Regeln und Methoden fr den Zyklus oder die Inhalte bei den Passwortnderungen festlegen.

Einfhrung in die Benutzerverwaltung

359

4.1.1

Das Rollenkonzept

Wie Sie sich sicherlich vorstellen knnen, kann so ein Benutzerprofil wegen des Umfangs der in der Datenbank gespeicherten Objekte aber auch aufgrund der Vielzahl der mglichen Einzelrechte ziemlich umfangreich sein. Gesellt sich jetzt auch noch der Umstand dazu, dass es in der Datenbank nicht nur ein paar, sondern stattdessen sogar mehrere hundert Anwender gibt, dann geht das schnell zu Lasten der bersicht oder Wartbarkeit. Die Verwendung von Einzelrechten entbehrt des weiteren jeglicher Vernunft, wenn man sich anschaut, dass sich die einzelnen Benutzer-Ids in der Praxis vor allem nur durch Ihre Kennung und die Passwrter unterscheiden, oder zumindest zu greren derartigen Gruppen zusammengefasst werden knnen. Aus diesem Grund bietet Ihnen Oracle das Konzept der Rollen an, mit dem Sie beliebige Einzelrechte zu Gruppen, den sogenannten Rollen, zusammenfassen knnen. Danach, d.h. in einem zweiten Schritt, knnen Sie den Benutzern die zuvor geschnrten Bndel von Einzelrechten zuweisen. Auf diese Weise werden nicht nur die einzelnen Benutzerprofile transparenter, sondern die gesamte Profilstruktur der Datenbank ist leichter zu durchschauen und in gewissen Teilen auch wiederverwendbar. Dies kann in der Praxis dadurch erreicht werden, dass zunchst kleine und mehrfach verwendbare Zugriffspakete zu entsprechenden Rollen gepackt werden. Da eine Rolle selbst wieder verschiedene Rollen im Profil enthalten kann, knnen in einem zweiten oder sogar dritten Schritt diese kleinen Rllchen zur anwendbaren Profilen gemischt werden, bevor der konkrete Benutzer letztendlich eine oder mehrere dieser Rollen zugewiesen bekommt.

4.1.2

Der Oracle Security Manager

hnlich wie bei den Datenbankobjekte finden Sie auch zur Bearbeitung der Benutzerprofile ein geeignetes Hilfsmitteln in Ihrem Oracle-Werkzeugkasten. Das gilt zumindest dann, wenn Sie den Enterprise Manager installiert haben, denn im Rahmen dieser Produktpalette finden Sie den sogenannten Security Manager (vgl. Abb. 4.1), mit dessen Hilfe Sie Benutzer, Rollen und Profile definieren bzw. bearbeiten knnen. Der Aufbau und die Funktionsweise des Security Managers entspricht im Wesentlichen den anderen Programmen aus der Gruppe des Enterprise Managers. Im linken Teil des Arbeitsfensters finden Sie wieder eine Liste, in der die vorhandenen Benutzer, Gruppen und Profile dargestellt werden. Nach der Markierung eines dort gezeigten Eintrags erhalten Sie im rechten Teil des Programmfensters die Mglichkeit, das ausgewhlte Objekt zu bearbeiten. Die dabei gezeigten Fenster und Reiter hngen natrlich von dem markierten Objekt ab, d.h. ein Profil besitzt logischerweise andere Einstellparameter als eine Rolle oder ein einfacher Benutzer.

360

Benutzer und Rollen

Abbildung 4.1: Arbeitsfenster des Security Managers

Aber auch besondere andere Eigenschaften, die ich schon beim Schema Manager beschrieben hatte, finden Sie bei diesem Programm wieder. So knnen Sie das Programm beispielsweise wieder dazu verwenden, die zu einer Aktion zugehrigen SQL-Anweisungen auszuspionieren oder Sie protokollieren alle Ihre Aktivitten mit Hilfe der Log-Meneintrge, um das zugehrige Skript anschlieend zu archivieren. Wenn Sie mit einer 8i-Version arbeiten, dann finden Sie den Security-Manager wieder im neuen DBA Studio (vgl. Abb. 4.2), wobei die einzelnen verfgbaren Funktionen allerdings die gleichen sind. Im dargestellten Baum des DBA Studios finden Sie in der Kategorie Sicherheit die gleichen Eintrge wie beim Security Manager der 8er-Version. Dennoch ist es aus meiner Sicht trotz dieser brauchbaren Programme sinnvoll, die zum Bearbeiten von Benutzern und Rollen einsetzbaren SQL-Anweisungen zu kennen, da bei greren Anwendungen die Profile blicherweise nicht per Hand erstellt, sondern mit Hilfe entsprechender Programme oder Skripte generiert werden.

Benutzerverwaltung mit SQL

361

Abbildung 4.2: Benutzerverwaltung im DBA-Studio

4.2

Benutzerverwaltung mit SQL

In Oracle besteht genau wie in vielen andere Datenbanksystemen trotzt des vorhandenen Tools die Mglichkeit, die Benutzer und Rollen mit Hilfe spezieller SQLAnweisungen anzulegen bzw. zu bearbeiten. Das Schne dabei ist, dass man sich hierfr kaum spezielle Befehle merken muss, denn hnlich wie die Anlage, das ndern oder Lschen von sonstigen Datenbankobjekten beginnen die Befehle zur entsprechenden Benutzerbearbeitung auch mit create, alter und drop. Generell handelt es sich bei den hier gezeigten Klauseln zu den einzelnen Befehlen mal wieder um einen Auszug der insgesamt vorhandenen Mglichkeiten, d.h. es lohnt sich unter Umstnden, die genaue Bandbreite der Anweisung in der OracleDokumentation nachzulesen, wobei Sie alle verfgbaren Parameter beispielsweise in der SQL-Referenz finden. Sofern nichts anderes vorgegeben ist, finden Sie die einzelnen Listings auch wieder auf der CD im \USER-Verzeichnis. Die Namen entsprechen dabei dem Listingnamen zuzglich der Namenserweiterung SQL.

4.2.1

Einen Benutzer bearbeiten

Im Listing 4.1 finden Sie die typische Befehlsabfolge zum Lschen und Anlegen eines neuen Datenbankbenutzers, wobei das hier verwendete Beispiel wieder dem im Kapitel 2 verwendeten Skript zur Anlage unseres Schema-Benutzers entspricht.

362

Benutzer und Rollen

drop user ubeispiel1 cascade; commit; / create user ubeispiel1 identified by manager default tablespace usr temporary tablespace temporary profile default account unlock quota unlimited on usr quota unlimited on indx quota unlimited on temporary; commit;
Listing 4.1: Typisches Skript zur Anlage eines Datenbankbenutzers

Wie Sie dem Listing 4.1 entnehmen knnen, wird ein Benutzers mit Hilfe der Anweisung drop user aus der Datenbank gelscht. Dabei sorgt die cascade-Klausel dafr, dass dies auch dann funktioniert, wenn der Benutzer Eigentmer irgendwelcher Datenbankobjekte, beispielsweise Tabellen ist, wobei die hierbei anschlieend ebenfalls aus der Datenbank entfernt werden. Die Anlage eines Benutzers erfolgt mit Hilfe der Anweisung create user, wobei Sie neben der neuen Benutzerkennung vor allem auch die identified by-Klausel zur Vorgabe des zugehrigen Passworts verwenden sollten. Alle anderen Parameter knnen Sie auch in einem zweiten Schritt durch das Absetzen entsprechender alter user-Anweisungen einstellen (vgl. Listing 4.2), wobei Sie die Bedeutung der einzelnen Klauseln der Tabelle 4.1 entnehmen knnen.
create user ubeispiel1 identified by manager; alter user ubeispiel1 default tablespace usr temporary tablespace temporary profile default account unlock quota unlimited on usr quota unlimited on indx quota unlimited on temporary;
Listing 4.2: Alternative Anlage eines neuen Benutzers

Klausel default tablespace

Beschreibung legt einen Standard-Tablespace fest (Standard system), der immer dann verwendet wird, wenn Sie bei der Anlage neuer Datenbankobjekte keine explizite Spacevorgabe vornehmen. In dem hier spezifizierten Tablespace werden temporre Objekte (z.B. Zwischenergebnisse) gespeichert.

temporary tablespace

Benutzerverwaltung mit SQL

363

Klausel profile account

Beschreibung Name des zugeordneten Profils (z.B. default). Freigabe oder Sperren des Benutzerprofils. Der Zusatz lock fhrt zur Sperrung des in der Datenbank verbleibenden Profils, wohingegen es mit unlock freigegeben wird. Mit Hilfe dieser Klausel knnen Sie festlegen, wie viel Platz ein Benutzer mit seinen Objekten in dem spezifizierten Tablespace belegen darf. Diese Vorgabe kann wie in unserem Beispiel uneingeschrnkt oder in Form einer festgelegten Anzahl von Kilo- oder Megabytes festlegen. Haben wir zwar nicht zusammen mit der alter user-Anweisung verwendet, aber auf diese Weise knnten Sie das Passwort fr einen vorhandenen Benutzer ndern.

quota

identified by

Tabelle 4.1: Beschreibung einiger Klauseln zur Verwendung in einem Benutzerprofil

4.2.2

Rollen anlegen und bearbeiten

Zum Bearbeiten einer Rolle bentigen Sie zunchst einmal nur die beiden Kommdos drop role und create role, mit denen Sie eine vorhandene Rolle lschen bzw. eine neue Rolle anlegen knnen. Das Listing 4.3 zeigt das einmal an einem einfachen Beispiel, wobei die Rolle in dem Beispiel ohne spezielles Passwort angelegt wird, so dass sie spter auf einfache Weise aktiviert werden kann.
drop role personal; create role personal;
Listing 4.3: Lschen und Anlegen einer Rolle

4.2.3

Profile anlegen und bearbeiten

Auch Profile knnen Sie mit Hilfe von SQL-Anweisungen anlegen, ndern oder lschen. Das Listing 4.4 zeigt das einmal anhand eines einfachen Beispiels, in dem das neue Profil aushilfe erstellt wird.
drop profile aushilfe cascade; create profile aushilfe limit sessions_per_user 1 private_sga 200K;
Listing 4.4: Lschen und Anlegen des Profils aushilfe

Das neue Profil erhlt einmal abgesehen von zwei Ausnahmen fr alle anderen Parameter Standardeinstellung, da diese nicht im Rahmen der Anlage mit speziellen Werten eingestellt werden. Die Anlage des neuen Profils erfolgt durch die Anweisung create profile, wonach der Name des neuen Profils und anschlieend das Schlsselwort limit folgt. Im Anschluss daran erfolgt die Aufzhlung der einzu-

364

Benutzer und Rollen

schrnkenden Parameter, wobei ich in unserem Beispiel vor allem dafr gesorgt habe, dass sich Benutzer mit diesem Profil nur einmal an der Datenbank anmelden knnen. Vor der Anlage des neuen Profils erfolgte in unserem Beispielskript die Lschung desselben mit Hilfe einer drop profile-Anweisung. Hierbei knnen Sie hnlich wie bei den Benutzern wieder die Klausel cascade verwenden, um sicherzustellen, dass das Profil trotzt eventueller Verwendung gelscht wird. Hierbei erhalten alle Benutzer, die das gelschte Profil aktuell besitzen, automatisch default als ihr neues Profil zugewiesen. Genau wie beim Anlegen neuer Benutzer haben Sie auch bei den Profilen die Mglichkeit, dieses zunchst einmal recht nackt anzulegen und die einzelnen Parameter in einem zweiten Schritt durch entsprechender alter profile-Befehle zu verndern (vgl. Listing 4.5).
alter profile aushilfe limit failed_login_attempts 5 password_lock_time 1;
Listing 4.5: Verndern eines Profils mit Hilfe entsprechender alter-Kommandos

Des letzte Beispiel kontrolliert die Anzahl der fehlerhaften Anmeldeversuche und sperrt den Benutzer nach fnf vergeblichen Versuchen fr einen Tag. Diese und weitere interessante Profileinstellungen knnen Sie der Tabelle 4.2 entnehmen.
Profilparameter sessions_per_user connect_time idle_time failed_login_attempts password_life_time Beschreibung Anzahl der Sitzungen, die ein Benutzer parallel in der Datenbank betreiben kann. Maximale Lebensdauer einer Datenbanksitzung in Minuten. Anzahl der Minuten, nach der eine inaktive Sitzung aus dem System geworfen wird. legt die Anzahl der mglichen vergeblichen Anmeldeversuche fest, bevor die Benutzerkennung gesperrt wird. gibt die maximale Lebensdauer fr ein Passwort in Tagen an, d.h. nach Ablauf dieser Zeit muss das Passwort vom Benutzer gendert werden. In dem Zusammenhang sind vielleicht auch die beiden Parameter password_reuse_time und password_reuse_max interessant, mit denen die Wiederverwendbarkeit von abgelaufenen Passwrtern gesteuert werden kann. Das gleiche gilt fr den Parameter password_grace_time, mit dem Sie entsprechend der eingestellten Tage vor dem Ablaufen des Kennworts eine Warnmeldung generieren knnen. Anzahl der Tage, fr die eine Benutzerkennung nach einer Sperre wegen fehlerhafter Anmeldeversuche, gesperrt bleibt. Mit Hilfe dieses Parameters knnen Sie in Ihrem System eine Funktion zur berprfung vergebener Passwrter installieren.

password_lock_time password_verify_function

Tabelle 4.2: Auszug aus den vorhandenen Profilparametern

Benutzerverwaltung mit SQL

365

Vor allem der letzte Parameter drfte doch so richtig nach dem Geschmack deutscher Revisionsmitarbeiter sein, denn er ermglicht uns, die Regeln fr die Passwortvergabe so komplex zu gestalten, dass wir Techniker anschlieend wieder sicher sein knnen, die meisten Kennwrter auf einem Zettel unter der Schreibtischunterlage oder der Tastatur zu finden. Mit Hilfe einer Funktion, die Sie innerhalb des sys-Schemas anlegen mssen, knnen Sie in der Datenbank bzw. fr die Benutzer des zugehrigen Profils ein beliebiges Programm fr die Passwortberprfung installieren. Wie das genau geht, das will ich Ihnen anhand einer sehr einfachen Funktion gerne einmal zeigen und daher habe ich im Listing 4.6 eine einfache Prffunktion kodiert.
create or replace function sys.test_kennwort ( benutzer varchar2, password varchar2, altes_password varchar2) return boolean is begin if password = 'HURRA' then raise_application_error(-20002, 'Das Kennwort ist doof!!'); else return true; end if; end;
Listing 4.6: Erstellen einer Prffunktion fr Kennwrter

Wie Sie dem Listing 4.6 entnehmen knnen, heit meine Passwortprffunktion sys.test_kennwort und erhlt beim Aufruf drei Parameter vom Datentyp varchar2, wobei der Rckgabetyp der Funktion vom Datentyp boolean ist, so dass die Funktion lediglich true (=wahr, Kennwort ist ok) und false (=falsch, Kennwort falsch) zurckliefern kann. Im nchsten Schritt mssen Sie die Prfroutine in einem Profil, beispielsweise default, installieren. Wie das geht, dass knnen Sie dem nchsten Listing (vgl. 4.7) entnehmen.
alter profile default limit password_verify_function test_kennwort;
Listing 4.7: Installation der neuen Passwortroutine

Nun gibt es aber kein Halten mehr und wir wollen im nchsten Schritt unsere neue Superroutine ausprobieren, indem wir das Kennwort irgendeines Benutzers ndern. Wie das geht und was dabei logischerweise passiert, das sehen Sie im Listing 4.8, in dem wir mit Hilfe der typischen alter user-Anweisung das Passwort ndern.

366

Benutzer und Rollen

alter user ubeispiel identified by HURRA; ORA-28003: password verification for the specified password failed ORA-20002: Ich finde das Kennwort doof!!
Listing 4.8: Knock-Out, unsere neue Funktion mischt sich bei der Passwortvergabe ein

4.3

Rechtevergabe mit SQL

Die erstellten Profile werden bei der Anlage eines Benutzers bzw. mit Hilfe eines entsprechenden alter user-Befehls den Benutzerkennungen zugewiesen oder das System verwendet das default-Standardprofil, sofern keine spezielle Profil-Einstellungen vorgenommen wird. Dennoch ist man nach der Anlage einer Rolle oder eines Benutzers noch weit von einer funktionierenden Kennung entfernt, denn anschlieend ist der neue Benutzer zwar im System angelegt, aber drfen darf er bisher noch gar nichts. Das ndert sich erst, indem einer Rolle spezielle Rechte, die Rolle dem Benutzer oder dem Benutzer direkt spezielle Privilegien zugewiesen werden.

4.3.1

Vergabe von Einzelrechten und Rollen

Die Vergabe von Einzelrechten erfolgt grundstzlich mit Hilfe der grant-Anweisung, wohingegen fr die Entziehung von Privilegien der Befehl revoke zur Verfgung steht. Natrlich darf nicht jeder Benutzer eine weitere Kennung anlegen oder irgendwelche Privilegien an andere Benutzer weitergeben, sondern hierzu muss er entweder die notwendigen Systemrechte besitzen oder er muss Besitzer derjenigen Datenbankobjekte sein, fr die er anderen Anwendern Zugriffsrechte erteilt. Zugriffsrechte auf Tabellen Wie Sie wissen, werden die in der Datenbank gespeicherten Tabellen mit Hilfe der DML-Anweisungen (DML = Data Manipulation Language) insert, update und delete gendert und durch ein select-Kommando abgefragt. Die bei den Tabellen vorhandene Rechteverwaltung entspricht dabei genau diesen vier Mglichkeiten, d.h. Sie knnen die Verwendung jede dieser vier Anweisungen separat freigeben. Die Anwendung der grant-Anweisung entspricht dabei dem folgenden Schema:
grant <DML-Kommando> [(Feldliste)] on <Tabellenname> to <Benutzerkennung oder Rolle>

Die in dem Schema gezeigte Feldliste existiert allerdings nur fr die beiden Anweisungen insert und update, so dass Sie das ndern oder Erweitern einer Tabelle auf spezielle Felder einschrnken knnen. Ein solches restriktives Einfgen macht natrlich nur dann Sinn, wenn das aufgrund der Tabellenstruktur berhaupt mglich ist, d.h. die nicht im Zugriffsprofil enthaltenen Spalten mssen entweder den besonderen Wert null vertragen oder ber einen Standardwert versorgt werden.

Rechtevergabe mit SQL

367

Innerhalb einer grant-Anweisung knnen mehrere DML-Zugriffsrechte fr eine Tabelle erteilt werden, indem die einzelnen zugelassenen Kommandos durch Komma getrennt aufgezhlt werden. Ein Beispiel fr die konkrete Anwendung knnen Sie dem Listing 4.9 entnehmen, indem der Rolle personal verschiedene Rechte fr die Tabelle personalien erteilt werden.
grant select, update (name, strasse1, strasse2, strasse3, strasse4, ort, plz), delete, insert on personalien to personal;
Listing 4.9: Erteilung von Zugriffsrechten auf eine Tabelle

In diesem Beispiel erhlt die Rolle personal fast vollen Zugriff auf die Personalstammdaten. Einzige Ausnahme ist die Einschrnkung der nderungsberechtigung auf die Anschriftenfelder. Das hier gezeigte Beispiel wre in der Praxis natrlich mehr als fragwrdig, denn wenn ich Lschen und Neuanlegen darf, dann kann ich mit entsprechendem Mehraufwand auch jede nderung durchfhren. Sofern das dann also doch zu viele Rechte fr den Zugriff auf die gespeicherten Personalien waren, dann knnen Sie das Zugriffsprofil mit Hilfe der revoke-Anweisung jederzeit wieder einschrnken. In unserem Beispiel (vgl. Listing 4.10) entziehen wird der Rolle personal wieder den Lsch- und Einfgezugriff auf diese Tabelle.
revoke delete, insert on personalien from personal;
Listing 4.10: Entzug von Zugriffsrechten mit Hilfe des revoke-Befehls

An diesem Beispiel sehen Sie, dass sich die Anwendung von revoke eigentlich kaum vom grant unterscheidet, d.h. im Prinzip mssen eigentlich nur das Schlsselwort to gegen das neue Wrtchen from austauschen. Allerdings mssen Sie beachten, dass sich die Zugriffsrechte auf die Tabellen nicht spaltenweise entziehen lassen, d.h. bei einer nderung eines spaltenbezogenen update-Rechts, mssen Sie dieses in der neuen Spezifikation erneut freigeben oder vollstndig entziehen. Die Verwendung des revoke-Kommandos entspricht somit also folgendem Schema:
revoke <DML-Kommando> on <Tabellenname> from <Benutzerkennung oder Rolle>

Die hier beschriebene Anwendung der beiden Befehle grant und revoke gilt natrlich nicht nur explizit fr Tabellen, sondern fr alle Objekte, die mit den aufgefhrten DML-Kommodos gendert oder abgefragt werden knnen, was vor allem zusammen mit der Verwendung von Synonymen oder Views interessant ist. Auerdem knnen Sie anstelle der in meinem Beispiel verwendeten Rolle auch die Kennung eines beliebigen Benutzers angeben, ohne dass die Befehle ansonsten in irgendeiner Form gendert werden mssten.

368

Benutzer und Rollen

Die Leseberechtigung auf eine View beinhalten brigens auch automatisch den impliziten Zugriff auf die dahinterliegenden Tabellen, d.h. die explizite Bercksichtung der Tabellen im Zugriffsprofil ist nicht notwendig. Das gilt sogar prinzipiell fr alle aufeinander aufbauenden Objekte, d.h. wenn Sie eine Prozedur ausfhren drfen, in der eine spezielle Tabelle gelesen wird, dann bentigen Sie nicht unbedingt auch einen expliziten Zugriff auf diese Tabelle. Ausfhrungsrechte von Funktionen und Prozeduren Das Starten der in der Datenbank gespeicherten ausfhrbaren Objekte wie Funktionen oder Prozeduren wird ebenfalls mit Hilfe der grant-Anweisung in der Variante execute erlaubt, bzw. mit Hilfe der entsprechenden revoke-Anweisung wieder entzogen. Dem folgenden Beispiel in Listing 4.11 knnen Sie entnehmen, wie der Rolle personal das Recht zur Ausfhrung der Funktion get_fieldlist erteilt wird.
grant execute on get_fieldlist to personal;
Listing 4.11: Starten einer Funktion freigeben

Das Ganze funktioniert entsprechend fr Prozeduren und Pakete, wobei Sie bei den Paketen bercksichtigen mssen, dass hierbei natrlich immer alle enthaltenen Prozeduren und Funktionen freigegeben werden. Alles erlauben Wie Sie gesehen haben, unterscheiden sich die Freigaben auf Tabellen oder Prozeduren kaum voneinander und funktionieren zumindest ab dem on-Schlsselwort exakt gleich. Es gibt daher fr die Anwendung des grant-Kommondos sogar noch einmal eine Vereinfachung, wenn man fr das jeweils spezifizierte Objekte den vollen Zugriff gewhren will. Erlaube fr das genannte Objekt alles, was mit ihm geht; in diesem Sinne knnen Sie die Schlsselwrter execute, select, update usw. einfach durch das neue Wrtchen all ersetzen, so dass die Rechtevergabe fr die in der Datenbank gespeicherten Objekte jetzt immer nach dem gleichen Schema erfolgt:
grant all on <Objektliste> to <Benutzerkennung oder Rolle>

Auf die gleiche Weise knnen Sie natrlich auch beim Entzug von Einzelrechten vorgehen, was hierbei den zustzlichen Vorteil hat, dass Sie sich nicht darum kmmern mssen, ob die zu entziehenden Rechte berhaupt vergeben wurden. So fhrt die Anweisung
revoke select on bvs from ubeispiel1; ORA-01927: cannot REVOKE privileges you did not grant

beispielsweise zu einer Fehlermeldung, da das hier spezifizierte Recht bislang noch gar nicht erteilt wurde, wohingegen die Entziehung aller Rechte in jedem Fall einwandfrei funktioniert.
revoke all on bvs from ubeispiel1;

Rechtevergabe mit SQL

369

Systemrechte vergeben Die umfangreich vorhandenen Systemrechte werden ebenfalls mit Hilfe der grantAnweisung verliehen und mittels revoke-Befehl wieder entzogen. Allerdings wandelt sich hierbei das Schema der grant-Anweisung ein wenig und entspricht folgendem Aufbau:
grant <Systemrecht> to <Benutzerkennung oder Rolle>

Der Entzug eines Systemrechts mittels revoke-Befehl entspricht diesem Schema wieder weitgehend, d.h. auer dass Sie grant durch revoke ersetzen, mssen Sie auch noch das Schlsselwort to durch das Wrtchen from austauschen. Das nachfolgende Beispiel (vgl. Listing 4.12) zeigt Ihnen die Anwendung dieser grant-Variante, indem der Rolle personal das Systemrecht create session zum Anmelden an die Datenbank zugewiesen wird.
grant create session to personal;
Listing 4.12: Vergabe von Systemrechten

Natrlich knnen Sie auch mehrere Systemrechte wieder gleichzeitig mit einer grant-Anweisung zuteilen oder mit einem revoke-Befehl entziehen, wobei Sie in beiden Fallen die zu bercksichtigenden Rechte durch Komma getrennt aufzhlen mssen. An dieser Stelle knnte man nun die nchsten drei Seiten damit fllen, eine bersicht der vorhandenen Systemrechte in Form einer entsprechenden Tabelle darzustellen. Das hiee aber abschreiben, denn eine solche Tabelle ist schon in der Oracle-Dokumentation enthalten. Sie finden sie dort im Buch Oracle8 SQL Reference unter der Beschreibung des grant-Kommandos. Schlagen Sie in der OnlineDokumentation im Index dieses Buches einfach den Begriff grant nach und folgenden Sie anschlieend dem Verweis system privilegs and roles to users. Rollen zuweisen Zur Zuweisung der Rollen gibt es eigentlich nichts Besonderes mehr zu sagen, auer dass sich eine Rolle in Bezug auf die Verwendung der grant- und revokeBefehle wie ein normales Systemrecht verhlt, d.h. mit der im Listen 4.13 gezeigten Variante weisen wir einem Benutzer die Rolle personal zu.
grant personal to ubeispiel1
Listing 4.13: Zuweisen einer Rolle zu einem Benutzerprofil

Mehr ist hierbei eigentlich nicht zu bercksichtigen, auer vielleicht, dass eine Rolle nicht unbedingt direkt einer Benutzerkennung, sondern auch einer anderen Rolle zugewiesen werden kann. Ebenfalls mssen Sie einem Benutzer als letzten Schritt nicht nur in Rollen gebndelte Profile zuweisen, sondern Sie knnen hierbei auch alle denkbaren Einzelrechte verwenden.

370

Benutzer und Rollen

Die Berechtigung, selbst Rechte zu vergeben Die Berechtigung, anderen Benutzern oder Rollen spezielle Zugriffsrechte zu erteilen, ist fr die im Besitz befindlichen Objekte quasi angeboren. Hat man also das Recht, in der Datenbank eine neue Tabelle anzulegen, dann hat man anschlieend auch das Recht darber zu entscheiden, wer auer einem noch Zugriff auf diese Tabelle erhlt. Des weiteren existieren spezielle Systemrechte, die einen Anwender priviligieren knnen, anderen Benutzern spezielle Rechte zu erteilen bzw. zu entziehen. Ein Beispiel hierfr sind die beiden Systemrechte grant any privilege und grant any role, mit denen Anwender zum Wchter vorhandener Rechte und Rollen wird. Will man nicht ganz so weit gehen, dann besteht als Alternative noch die Mglichkeit, nur die Weitergabe der zugewiesenen Rechte zu erlauben, indem diese mit dem Zusatz with admin option erteilt werden, d.h. die grant-Anweisung wird am Ende durch diese Klausel erweitert.
grant select, update (name, strasse1, strasse2, strasse3, strasse4, ort, plz), delete, insert on personalien to personal with admin option;

ffentliche Objekte Indem Sie den Zugriff auf ein Objekt fr den Pseudo-Benutzer public freigeben, wird fr dieses der ffentliche Zugriff installiert, d.h. anschlieend kann jeder Benutzer in der vorgegebenen Art- und Weise auf das Objekt zugreifen.
grant all on gehalt to public;

4.3.2

Zugriffsschutz auf Datensatzebene

Der bisher praktizierte Zugriffsschutz auf die in der Datenbank gespeicherten Objekte folgte meistens dem Motto ganz oder gar nicht. Einzige Ausnahme war vielleicht noch die Mglichkeit, eine nderungs- oder Einfgeanweisung auf spezielle Felder der Tabelle einzuschrnken. Ich beschftige mich in den letzten zehn Jahren berwiegend mit Personalsystemen (Planung und Abrechnung) und habe in dieser Zeit noch keinen Kunden gesehen, dem das gereicht htte. Das wenigste, was eigentliche alle bentigten war die Mglichkeit, den Zugriff auf einzelne Datenstze zu steuern, d.h. bestimmte Mitarbeitergruppen sollen nur von speziellen Benutzern gelesen oder bearbeitet werden knnen. Die Kriterien fr diesen Selektionsprozess folgen meistens organisatorischen oder hierarchischen Gegebenheiten, wobei sogar Mischformen mglich sind. Dem ersten Fall liegt der Gedanke zugrunde, dass Mitarbeiter einer bestimmten Abteilung oder eines Bereichs nur von den dort zustndigen Sachbearbeitern gelesen und

Rechtevergabe mit SQL

371

bearbeitet werden knnen. Den anderen Fall finde ich immer ein wenig belustigend, denn schlielich ist es doch ganz normal, dass man fr die Ansicht der besonders bunten Tiere im Zoo eine ganz spezielle Eintrittskarte bentigt. Doch nun wieder zum Ernst der Lage. So lange Sie auch in der Anwenderdokumentation Ihrer Datenbank suchen werden, Sie werden keine speziellen Befehle zur Parametrierung des satzbezogenen Zugriffs finden. Das ist, falls berhaupt, aber kein direkter Mangel der Oracle-Datenbank, sondern entspricht zumindest in den Datenbanken, die ich kenne, scheinbar dem momentanen Stand der Technik. Sofern Sie gerade eine sogenannte Standardsoftware wie beispielsweise SAP oder PeopleSoft einfhren, dann merken Sie von diesem Mangel natrlich recht wenig, da solche Produkte blicherweise ihre eigene Benutzer- und Sicherheitsverwaltung haben und einen datensatzbezogenen Zugriffsschutz innerhalb der zugehrigen Anwendungsprogramme regeln. Diese Beobachtung trifft allerdings nicht nur auf Datenschutzebene zu, sondern solche Produkte benutzten generell ziemlich wenig von den in Oracle vorhandenen Mglichkeiten, d.h. das gesamte Geschftsmodell ist nicht Bestandteil der Datenbank, sondern wird mit Hilfe der zur Anwendung gehrenden Programmlogik abgebildet. Die Datenbank selbst verkommt dabei zum dummen Datenfriedhof, d.h. Mitdenken und eigene Intelligenz sind unerwnscht. Das hat natrlich zur Folge, dass Sie mit Hilfe von Produkten Dritter zwar sicherlich Abfragen auf die Datenbank aber im Regelfall keine Eingaben durchfhren drfen, da in dem Fall die zu den Daten gehrende Prf- und Geschftslogik nicht ausgefhrt wird. Auerdem mssen Sie sich im ersten Fall auch wieder mit den Datenschutzproblematiken auseinandersetzen, d.h. es obliegt jetzt Ihnen, die vom Hersteller verdrngten Probleme anzugehen. Dabei ist das hier skizzierte Problem durchaus lsbar. Ich selbst habe mit einem Team einmal eine Anwendung entworfen und realisiert, in der neben den Daten auch die gesamte Geschftslogik und alle Datenschutzmechanismen enthalten waren, d.h. es war im laufenden Betrieb vllig egal, welche Eingaben mit welchen Produkten in der Datenbank durchgefhrt wurden. Was nun den satzbezogenen Zugriffsschutz angeht, so wird in einigen Standardlsungen der Ansatz verfolgt, eine spezielle View zu bauen, die innerhalb der Dialoganwendungen mit der eigentlichen Suchanfrage verknpft wird. Da man aufgrund der meistens vorhandenen Dialogfhrung auch nur das ndern kann, was zuvor gelesen wurde ist auf diese Weise auch sichergestellt, dass keine unberechtigten nderungen durchgefhrt werden knnen. Mit Hilfe der in der Datenbank verfgbaren Funktionalitten kann man aber auch noch einen Schritt weitergehen, indem man sich beispielsweise die Verhaltensweisen von Views als aktive Datenschutzkomponente verfgbar macht. Wie Sie wissen ist eine View eigentlich nichts anderes als eine ausfhrbar gespeicherte Abfrage, wodurch sich die Mglichkeit ergibt, die datensatzbezogenen Zugriffsbestimmungen innerhalb dieser View abzuspeichern.

372

Benutzer und Rollen

Das knnte man zum einen so realisieren, dass jeder Benutzer fr den Zugriff auf die Tabellen eine eigene View erhlt, in der die erlaubten Datenstze mit Hilfe der gespeicherten Abfrage ermittelt werden.
create or replace view ubeispiel1_personalien as select * from personalien where name between 'A' and 'C';

Anschlieend erhlt der entsprechende Benutzer lediglich die Berichtigung, die in der Datenbank vorhandenen Personalien durch seine individuelle Brille zu betrachten, was Sie mit Hilfe der folgenden grant- bzw. revoke-Anweisung realisieren knnen:
revoke all on personalien from ubeispiel1; grant all on ubeispiel1_personalien to ubeispiel1;

Anschlieend kann unser neuer Benutzer nur noch Mitarbeiter entsprechend dem vorgegebenen Namensbereich bearbeiten, was in der Praxis dann folgendermaen aussieht.
SQLWKS> select persnr, name 2> from ubeispiel.ubeispiel1_personalien; PERSNR NAME ----------- -------------------------------------------------7000006 Beckmann,Yonne 7000018 Bruckner,Yonne 7000021 Btzing,Brbel 3 rows selected.

Natrlich mssen Sie bei diesem Verfahren die View immer dann neu erstellen, wenn sich die den Zugriffsschutz bestimmenden Regelwerke ndern, jedoch knnte man hierfr ein entsprechendes Programm entwickeln, dass fr neue Benutzer oder sich ndernden Zugriffsrechten die bentigten Views automatisch generiert und selbst das eintippen des SQL-Textes einer solchen View ist nicht schwieriger als das, was den Sicherheits-Administratoren in Standardanwendungen teilweise abverlangt wird. Trotzdem kann man ein solches Zugriffssystem sicherlich auch komfortabler und damit aber aus technischer Sicht auch komplexer gestalten, indem man in die Datenbank Methoden implementiert, die den Zugriffsschutz zur Laufzeit interpretieren. Der erste Schritt, so etwas zu realisieren, besteht zunchst einmal darin, die Zugriffsberechtigungen mit Hilfe spezieller Tabellen in der Datenbank zu beschreiben. Entsprechend unserem einfachen Beispiel knnte das folgendermaen aussehen (vgl. Listing 4.14).
drop table pers_sec; create table pers_sec ( userid varchar2(15) not null, name_von varchar2(15) not null,

Rechtevergabe mit SQL

373

name_bis varchar2(15) not null, constraint pers_name_ck check (name_von <= name_bis), constraint pers_sec_pk primary key (userid, name_von) ); commit;
Listing 4.14: Anlegen einer Tabellen zum Speichern von Zugriffskriterien

Mit Hilfe der neuen Tabelle pers_sec sollen demnchst die auf Namen basierenden Zugriffsrechte verwaltet werden, so dass wir gleich einmal fr unseren Benutzer ubeispiel1 zwei Kriterien in die Datenbank einstellen.
insert into pers_sec values ('UBEISPIEL1','Aa','De'); insert into pers_sec values ('UBEISPIEL1','Fe','Rf');

Im nchsten Schritt mssen wir eine Funktionen (vgl. Listing 4.15) erstellen, mit deren Hilfe wir die Zugriffskriterien zur Laufzeit auswerten knnen.
create or replace function check_access(in_persnr in varchar2) return integer is raccess integer; begin raccess := 0; select count(*) into raccess from personalien a, pers_sec b where a.persnr = in_persnr and b.userid = user and a.name between b.name_von and b.name_bis; return raccess; end;
Listing 4.15: Erstellen unserer Sicherheitsfunktion

Unsere diesbezgliche Funktion heit check_access und erhlt beim Aufruf die zu berprfende Personalnummer als Parameter. Dabei ist der von der Funktion zurckgelieferte Wert nur dann Null (0), wenn der aktuelle Benutzer keinen Zugriff auf diesen Mitarbeiter hat. Das berprfen wir innerhalb der Funktion, indem wir die Personalien mit unserer Regeltabelle pers_sec verknpfen, die Personalien selbst mit Hilfe der bergebenen Personalnummer einschrnken und vor allem die Regeltabelle mit Hilfe der Pseudospalte user selektieren.
and b.userid = user

Diese Pseudospalte liefert die zur aktuellen Sitzung und damit die zur Abfrage passende Benutzerkennung. Es gbe sicherlich noch andere Mglichkeiten diesen Wert, beispielsweise ber die Session-Informationen, herauszubekommen, aber die Verwendung der Variablen ist der allereinfachste Weg.

374

Benutzer und Rollen

Nachdem wir nun die bentigten Kontrollfunktion fr den Lesezugriff programmiert haben, erstellen wir als Nchstes eine neue Leseview, die im Unterschied zur vorhergehenden Lsung von allen Datenbankbenutzern verwendet werden kann.
create or replace view read_personalien as select * from personalien where check_access(persnr) > 0;
Listing 4.16: Zweite Variante unserer Leseview mit satzbezogenem Zugriffsschutz

Jetzt mssen wir unserem Anwender ubeispiel1 geschwind noch Zugriff auf diese neue View erteilen, was wieder mit Hilfe einer gewhnlichen grant-Anweisung passiert:
grant select on read_personalien to ubeispiel1

Die Spannung steigt, denn jetzt probieren wir unsere Konstruktion aus und verwenden die neue Abfrage, nachdem wir uns als ubeispiel1 an der Datenbank angemeldet haben.
SQLWKS> select persnr, name 2> from ubeispiel.read_personalien; PERSNR NAME ----------- -------------------------------------7000002 Karlo,Armin-Helgo 7000003 Heiden,Magareta 7000004 Hardt,Andreas 7000005 Nibelungen,Ellen ... 7000010 Mller,Frida 7000013 Heler,Sascha 17 rows selected.
Listing 4.17: Ausprobieren des Zugriffsschutzes auf Datensatzebene

Wie Sie sehen, funktioniert unsere neue Variante des satzbezogenen Zugriffsschutzes prima, wobei das Verfahren in der Praxis zumindest in Dialogsystemen auch hinreichend schnell ist. Das liegt natrlich auch daran, dass normalerweise niemand im Dialog hunderte von Datenstzen auf einmal abruft, sondern aufgrund vorgegebener Suchbegriffe eine Handvoll Mitarbeiter vorselektiert werden, von denen anschlieend mit Hilfe unserer Funktion noch einmal verschiedene Datenstze herausgestrichen werden, weil die Funktion wegen des fehlenden Zugriffsrechts fr sie den Wert 0 zurckliefert. Fr den Batchbetrieb oder zur Erstellung besonderer Auswertungen bentigt man im Regelfall sowieso spezielle Benutzerkennungen, die meistens jenseits des blichen Zugriffschutzes funktionieren, so dass dieses bei groen Datenmengen etwas kopflastige Verfahren hierbei keine Rolle spielt.

Auswertung der Benutzerprofile

375

Ich habe einmal im Rahmen eines Projektes so etwas hnliches realisiert und die Reaktionszeit des Dialogs liegt bei allen Masken unter einer Sekunde, wobei ber 100.000 Mitarbeiter in der Datenbank gespeichert sind. Schreibschutz installieren Die Realisierung eines datensatzabhngigen Schreibschutzes knnte man im brigen auf ganz hnliche Weise realisieren, indem man entweder nderungsfhige Views baut, die in ihrer where-Bedingung die nderbaren Datenstze selektieren oder man installiert die bentigten Berechtigungsprfungen in entsprechenden Vorab-Triggern, so dass die nderungstransaktion zurckgerollt wird, wenn der Benutzer keine Berechtigung zu deren Durchfhrung hat. Ich persnlich wrde das zuletzt skizzierte Verfahren in jedem Fall vorziehen, werde hierfr in diesem Workshop allerdings kein Beispiel anbringen. Zum einen wrde das den Rahmen des Buches so langsam sprengen und zum anderen muss ja auch noch etwas fr meine Tagesarbeit als Anwendungsberater brigbleiben.

4.3.3

Benutzerverwaltung in der Praxis

Im Rahmen der letzten Kapitel haben Sie gesehen, wie Sie durch Verwendung eines Skriptes oder dem Security Manager bzw. dem DBA Studio von Oracle neue Benutzer in der Datenbank anlegen und mit Hilfe von Einzelrechten oder Rollen die zugehrigen Profile verwalten knnen. Logischerweise kann man auch fr diese Aufgabe zunchst entsprechende Anwendungstabellen in der Datenbank definieren, in denen die fr das Profil bentigten Daten mit Hilfe eines einfachen Anwendungsprogramms gespeichert werden. Die eigentliche Anlage der Benutzer bzw. die Zuweisung der einzelnen Objektrechte erfolgt dann im zweiten Schritt mit Hilfe eines entsprechenden PL/SQL-Programms. Im Rahmen des nchsten Buchabschnitts, wo wir uns ein wenig intensiver mit der PL/SQL-Programmierung beschftigen werden, habe ich hierzu ein passendes Beispiel geplant, wo Sie mit Hilfe einer Tabelle und einer Prozedur die bentigten Profile quasi auf Knopfdruck erstellen knnen.

4.4

Auswertung der Benutzerprofile

Im Kapitel 3.5.3 hatte ich schon die wichtigsten Systemviews aufgezhlt (vgl. Tabelle 3.14), mit denen Sie Auswertungen ber vorhandene Benutzer, Rollen und die jeweilig vergebenen Rechte durchfhren knnen. Ebenso hatte ich Ihnen damals noch das ein oder andere Beispiel fr die Anwendung dieser Views versprochen, was nun im Folgenden passieren soll. Zur Erinnerung mchte ich hier noch einmal kurz erwhnen, dass genau wie bei den Datenbankobjekten auch diese Views meistens wieder in drei Varianten zur Verfgung stehen, die sich namentlich durch die drei Prfixe dba, all und user und inhaltlich durch die von der View gelieferten Datenmengen unterscheiden. So eignen sich die user-Views lediglich zur Analyse des eigenen, aktuell angemeldeten

376

Benutzer und Rollen

Benutzers, wohingegen Sie mit Hilfe der dba-Abfragen jeden angelegten Benutzer betrachten knnen. Definierte Benutzer und Rollen Wie schon gesagt, eignen sich die beiden Views dba_users und dba_roles, um einen berblick ber die in der Datenbank angelegten Benutzer und Rollen zu erhalten. Im Prinzip erhalten Sie mit Hilfe dieser Sichten alle Felder zurck, die Sie bei der Anlage mit Hilfe der entsprechenden create-Befehle vorgeben konnten, und da die Anwendung auch ansonsten nichts interessantes mehr zu Tage frdert bzw. nicht weiter schwierig ist, mchte ich an dieser Stelle auf eine Demonstration verzichten. Entsprechend einfach ist auch die Auswertung eines Profils mit Hilfe der View dba_profiles. Sie liefert fr jeden spezifizierten Parameter (ressource_name) einen eigenen Datensatz, wobei Sie die vorhandene Einstellung dem Wert limit entnehmen knnen.
select ressource_name, limit from dba_profiles where profile = 'DEFAULT'

Vergebene Systemrechte ermitteln Um zu ermitteln, welche direkt zugewiesenen Systemrechte ein Benutzer hat, knnen Sie eine Abfrage auf die View dba_sys_privs erstellen (vgl. Listing 4.18). Allerdings mssen Sie dabei beachten, dass man Systemrechte auch indirekt ber eine Rolle erhalten kann. Dieses Problem wird uns im Folgenden bei der Auflsung von Benutzerprofilen permanent begleiten, d.h. wir haben bestimmte Einzelrechte und beliebig viele zugewiesene Rollen, die wiederum beliebige Einzelrechte oder weitere Rollen beinhalten.
SQLWKS> select * from dba_sys_privs where grantee = 'SYSTEM' 2> GRANTEE PRIVILEGE ADM ------------------------------ ------------------------------------ --SYSTEM UNLIMITED TABLESPACE YES 1 row selected.
Listing 4.18: Ermittlung direkt zugewiesener Systemrechte

Die zugewiesenen Rollen ermitteln Die in einem Benutzerprofil enthaltenen Rollen erhalten Sie durch einen Zugriff auf die View dba_role_privs, wie Sie dem folgenden Beispiel (vgl. Listing 4.19) entnehmen knnen.
SQLWKS> select grantee, granted_role, admin_option 2> from dba_role_privs 3> where grantee = 'SYSTEM';

Auswertung der Benutzerprofile

377

GRANTEE -----------------------------SYSTEM SYSTEM 2 rows selected.

GRANTED_ROLE -----------------------------DBA RBEISPIEL

ADM --YES YES

Listing 4.19: Auswertung der direkt zugewiesenen Rollen

Das Rollengeflecht zerlegen Wie Sie wissen, muss eine Rolle nicht nur bzw. gar nicht aus Einzelrechten bestehen, sondern kann wiederum beliebige Rollen enthalten. Die in einer Rolle enthaltenen Rollen erhalten Sie durch eine Abfrage der View role_role_privs, wofr Sie im Listing 4.20 ein entsprechendes Beispiel finden.
SQLWKS> select * 2> from role_role_privs where role = 'RBEISPIEL'; 3> ROLE GRANTED_ROLE ------------------------------ -----------------------------RBEISPIEL EXP_FULL_DATABASE RBEISPIEL IMP_FULL_DATABASE RBEISPIEL RESOURCE 3 rows selected.
Listing 4.20: Ermitteln der einer Rolle zugewiesenen Unterrollen

ADM --YES YES YES

Systemrechte einer Rolle ermitteln Zur Ermittlung der einer Rolle zugewiesenen Systemrechte werden Sie keine spezielle View im Datenhaushalt von Oracle finden, denn die knnen Sie wieder mit Hilfe der schon verwendeten Abfrage auf die Sicht dba_sys_privs ermitteln, indem Sie anstelle einer Benutzerkennung jetzt einfach den Namen der Rolle als Selektionskriterium verwenden.
... where grantee = 'DBA'

Zugriffsrechte auf Datenbankobjekte Neben verschiedenen Systemrechten werden im Rahmen eines Benutzerprofils vor allem Zugriffsrechte auf die in der Datenbank gespeicherten Objekte vorgehalten. Diese zugeteilten Objektrechte knnen Sie dem System mit Hilfe einer Abfrage auf die View dba_tab_privs entlocken, wofr Sie im Folgenden wieder ein kleines Beispiel finden.
SQLWKS> select table_name, privilege 2> from dba_tab_privs 3> where grantee = 'UBEISPIEL1'; 4>

378

Benutzer und Rollen

TABLE_NAME -----------------------------UBEISPIEL1_PERSONALIEN UBEISPIEL1_PERSONALIEN UBEISPIEL1_PERSONALIEN UBEISPIEL1_PERSONALIEN READ_PERSONALIEN 5 rows selected.

PRIVILEGE ---------------------------------DELETE INSERT SELECT UPDATE SELECT

Listing 4.21: Auswerten der fr einen Benutzer vorhandenen Objektberechtigungen

Die von dieser Abfrage gelieferte Spalte table_name sollten Sie nicht ganz so wrtlich nehmen, denn dort werden neben Tabellen auch Views, Synonyme oder Funktionen und Prozeduren angezeigt, wobei Sie in den beiden letzten Fllen dann als eingestelltes Privileg natrlich den Wert EXECUTE vorfinden. Anstelle eines Benutzernamens knnen Sie die Abfrage auch zusammen mit einer Rolle verwenden und erhalten in dem Fall die der Rolle zugewiesenen Objektberechtigungen. Spaltenbezogene Rechte Sofern die vergebenen Rechte nicht fr das ganze Objekt, sondern stattdessen fr einzelne Spalten zugewiesen wurden, dann finden Sie die Zuweisungne nicht in der View dba_tab_privs, sondern stattdessen in der Sicht dba_col_privs, wobei jetzt alle zugewiesenen Spalten mit den jeweiligen Rechten aufgelistet werden. Genau wie in dem letzten Beispiel besteht auch hierbei wieder die Mglichkeit, die View zusammen mit einer Benutzerkennung oder einer Rolle zu verwenden.
SQLWKS> select table_name, privilege 2> from dba_col_privs 3> where grantee = 'PERSONAL'; 4> TABLE_NAME PRIVILEGE ------------------------------ -----------------------------PERSONALIEN UPDATE PERSONALIEN UPDATE PERSONALIEN UPDATE PERSONALIEN UPDATE PERSONALIEN UPDATE PERSONALIEN UPDATE PERSONALIEN UPDATE 7 rows selected.
Listing 4.22: Auswerten der erteilten Zugriffsrechte auf Spaltenebene

Anzeigen aller Berechtigten fr eine Tabelle Wie Sie den bisherigen Beispielen entnehmen konnten, ist die Abfrage einzelner Teilinformationen der Benutzerprofile nicht sonderlich schwierig, da die diesbe-

Auswertung der Benutzerprofile

379

zglich vorhandenen Views nicht sonderlich komplex sind. Das eigentliche Problem entsteht eigentlich erst dadurch, dass aufgrund der mglichen Schachtelungen die gesamten Profildefinitionen nicht in einem Rutsch gelesen werden knnen. So zeigt die folgende Abfrage (vgl. Listing 4.23) zwar, alle eingetragenen Zugriffsberechtigungen fr die Personalientabelle, jedoch werden in der Spalte grantee sowohl Benutzerkennungen als auch Rollen gezeigt.
SQLWKS> select grantor, grantee, privilege, column_name 2> from dba_col_privs 3> where owner = 'UBEISPIEL' and table_name = 'PERSONALIEN' 4> 5> union 6> 7> select grantor, grantee, privilege, '-' 8> from dba_tab_privs 9> where owner = 'UBEISPIEL' and table_name = 'PERSONALIEN'; 10> GRANTOR GRANTEE PRIVILEGE COLUMN_NAME ---------------------- --------------------- -------------- ----------UBEISPIEL PERSONAL SELECT UBEISPIEL PERSONAL UPDATE NAME UBEISPIEL PERSONAL UPDATE ORT UBEISPIEL PERSONAL UPDATE PLZ UBEISPIEL PERSONAL UPDATE STRASSE1 UBEISPIEL PERSONAL UPDATE STRASSE2 UBEISPIEL PERSONAL UPDATE STRASSE3 UBEISPIEL PERSONAL UPDATE STRASSE4 UBEISPIEL SYSTEM SELECT 9 rows selected.
Listing 4.23: berprfung der Zugriffsberechtigung auf die Personalien

In einem zweiten Schritt mssten jetzt noch die Rollen dahingehend aufgelst werden, dass jeder Benutzer ermittelt wird, der irgendwie im Besitz einer solchen Rolle ist, wobei das aufgrund der mglichen Schachtelungen noch einmal ein gutes Stck Arbeit sein kann.

PL/SQL-Programmierung

In den vorhergehenden Kapiteln haben Sie schon einen ersten Kontakt mit den PL/ SQL-Sprachelementen erhalten. Bei der Vorstellung verschiedener Datenbankobjekte wie Funktionen oder Trigger lie es sich gar nicht vermeiden, verschiedene PL/SQL-Routinen zu verwenden und damit diesem Kapitel vorzugreifen. Jetzt wollen wir die Verwendung dieser in der Datenbank enthaltenen Programmiersprache etwas genauer unter die Lupe nehmen und uns der PL/SQL-Programmierung ein wenig systematischer aber dennoch schnell nhern. Wenn Sie noch nie programmiert haben, dann sollten Sie damit allerdings nicht unbedingt jetzt beginnen, d.h. ich halte PL/SQL nicht fr die beste Wahl, um neben einer neuen Sprache auch das Programmieren in seinen Grundzgen zu erlernen. Das bedeutet aber auch nicht unbedingt, dass Sie jetzt zwangslufig noch ein weiteres Programmiersystem zum ben kaufen mssen. Zumindest sofern Sie mit NT arbeiten, knnen Sie ja mal spaeshalber ber das Men Start Ausfhren oder in einem MS-DOS-Fenster den Befehl qbasic eingeben. Hierdurch starten Sie den immer noch vorhandenen Basic-Interpreter, der sich aus meiner Sicht immer noch prima eignet, um zum einen erste Gehversuche im Programmierhandwerk zu unternehmen und zum anderen vielleicht ein weiteres Buch von mir zu kaufen. Alle in diesem Kapitel gezeigten Beispiele finden Sie wieder auf Ihrer Buch-CD, und zwar im Verzeichnis \PLSQL, wobei Sie in gewohnter Weise wieder fr jedes Beispiel (Listing) eine entsprechende Datei finden.

5.1
5.1.1

Einfhrung in PL/SQL
Allgemeines

Die meisten der aktuell verfgbaren Datenbanksysteme besitzen eine Spracherweiterung, mit deren Hilfe spezielle Kommandos und Funktionen ermglicht werden, die ber den reinen SQL-Umfang hinaus gehen. Zum Teil werden diese speziellen Befehle oder Funktionen auch gebraucht, um bestimmte Systemroutinen auszufhren und sind damit zwangslufig eng mit dem konkreten Datenbanksystem verbunden. Darber hinausgehend wird der Sprachumfang aber auch in allgemeinerer Form erweitert, so dass neben den reinen SQL-Operationen eine richtige Programmiersprache entsteht, was auch bei dem hier beschriebenen PL/SQL der Fall ist. Dennoch gibt es natrlich einen gravierenden Unterschied zu einer klassischen Programmiersprache, die blicherweise produktunabhngig fr alle mglichen Aufgabenstellungen verwendet werden kann. Das ist bei PL/SQL natrlich anders, denn die Verwendung dieser Sprache ist an die Oracle-Datenbank gebunden, d.h.

382

PL/SQL-Programmierung

neben einem speziellen Teil der Datenbank, der in der Lage ist SQL-Anweisungen zu interpretieren und auszufhren, gibt es auch noch einen anderen Teil, der ganze SQL-Programme ausfhren kann. Diesen Teil, die sogenannte PL/SQL-Engine, gibt es sogar in zwei Varianten, denn Sie haben die Mglichkeit PL/SQL-Programme auf dem Server, also innerhalb der Datenbankumgebung, oder auf dem Client auszufhren. In der Praxis werden PL/SQL-Programme eigentlich immer auf dem Server, d.h. im Datenbanksystem ausgefhrt, da ja gerade die Nhe zu den bentigten Daten den groen Vorteil dieser Programmiersprache ausmacht. Zusammen mit einigen Oracle-Tools erhlt man unter Umstnden aber auch eine PL/SQL-Engine fr den Client, wodurch sich PL/SQL-Programme etwas einfacher testen lassen und vor allem unabhngig vom Server entwickelt werden knnen. Datenbankskript versus Wirtstechnologie Eine oft verwendete Alternative zur Verwendung vollstndiger PL/SQL-Programme besteht in der Benutzung gewhnlicher Programmiersprachen (dem Wirt), in der die bentigten SQL-Routinen eingebettet werden. Das ist heute in nahezu allen gngigen Programmiersprachen mglich (z.B. C, Visual Basic oder Cobol), wobei es sogar Sprachen wie beispielsweise SQR gibt, die speziell auf diese Aufgabenstellung hin ausgerichtet sind. Die Entscheidung darber, welche dieser beiden Techniken konkret eingesetzt wird, hngt aus meiner Sicht von vielen verschiedenen Details der konkreten Frage- bzw. Aufgabenstellung ab und kann nicht pauschal beantwortet werden. Ich denke, dass man die folgenden Kriterien prfen bzw. bedenken sollte.

Wird das Programm hauptschlich dazu verwendet, um mit Hilfe von Konditionalbedingungen oder Schleifen die Ausfhrung bestimmter SQL-Abfragen zu steuern, so ist die eingebettete Verwendung in anderen Programmiersprachen durchaus sinnvoll. Das gilt vor allem dann, wenn fr die konkret zu verwendende Sprache entsprechendes Know How vorhanden ist. Schlielich kann die Einbettung ja sogar auch so weit gehen, dass ganze PL/SQL-Routinen wieder vom Wirtsprogramm aus an den Server gesendet werden, d.h. man verbaut sich durch diese Methode nicht die Verwendung komplexer PL/SQL-Anweisungsfolgen. Der groe Vorteil von reinen PL/SQL-Programme ist natrlich, dass diese automatisch zusammen mit der Datenbank in jede verfgbare Betriebsumgebung umziehen. Wechseln Sie also die Betriebsplattform, beispielsweise von NT-Server auf Unix, dann sind Ihre PL/SQL-Programme sofort verfgbar, was fr die selbsterstellten NT-Serverprogramme sicherlich nicht immer garantiert werden kann. Mssen im Rahmen der Programmierung hufig interdisziplinre Aufgabenstellungen angegangen werden (z.B. Lesen oder Erstellen von sequentiellen Dateien, Erstellen von Reports, Verbinden mit anderen Datenbanken oder Dialogsystemen), dann fllt die Verwendung reiner PL/SQL-Anwendungen aus meiner Sicht sowieso aus, da manche dieser Aufgabenstellungen nur umstndlich bzw. gar nicht lsbar sind.

Einfhrung in PL/SQL

383

Sofern bestimmte Abfragen hufig satzweise verarbeitet werden, dann sind reine PL/SQL-Programme bzw. zumindest entsprechende Routinen natrlich wieder im Vorteil, denn da Verarbeitung in dem Fall auf dem Server abluft, mssen keine Datenstze ber das Netzwerk bertragen werden. Auerdem besitzen Sie mit Ihrer Oracle-Datenbank auch alle notwendigen Hilfsmittel, regelmig wiederkehrende Jobs automatisch ablaufen zu lassen.

Grundstzliches zur Datenbankprogrammierung Wie Sie meinen Kriterien entnehmen knnen, habe ich berhaupt nichts gegen reine PL/SQL-Programme, aber ich finde herkmmliche Programme, in denen SQL-Anweisungen oder ganze PL/SQL-Routinen eingebettet sind allerdings genauso hbsch. Was mich vielmehr strt sind Anwendungen, die in den neuen Datenbankumgebungen nach althergebrachter Weise realisiert werden, d.h. im Rahmen des Programms wird eine Abfrage abgesetzt, jeder Datensatz empfangen und irgendwie verarbeitet, wobei diese Verarbeitung dann ebenfalls satzbezogen abluft, d.h. jeder gelesene Datensatz wird innerhalb einer externen Programmschleife per abgeschickter update-Anweisung verndert. Bei solchen Programmen merkt man auf den ersten Blick gar nicht, dass eine SQL-Datenbank angebunden ist, sondern stattdessen knnten auch sequentielle Dateien verarbeitet werden. Auerdem kann man ohne weitere Prfung behaupten, dass solche Programme meistens nicht laufzeitoptimal realisiert sind, d.h. wrde man die Aufgabenstellung anders angehen, dann kmen dabei schnellere Anwendungen heraus. Beim ersten Kontakt mit einem relationalen Datenbanksystem besteht die grte Herausforderung eines Anwendungsentwicklers nmlich darin, sich bei der Gestaltung seines Programms an eine mengenorientierte Verarbeitung zu gewhnen und die satzweise Abarbeitung von Ergebnissen nur noch im Ausnahmefall anzuwenden. Verwenden von PL/SQL-Kommandos Nach den vorhergehenden Worten zur Einstimmung, und bevor wir uns nun im Folgenden systematisch mit den verschiedenen Sprachkonstruktionen beschftigen, mchte ich jetzt noch einmal kurz zusammenstellen, wo Sie berall PL/SQLErweiterungen finden bzw. verwenden knnen.

Innerhalb eines Skripts knnen Sie entsprechende Befehle verwenden, um beispielsweise einen komplexen nderungscursor zu programmieren oder in Abhngigkeit verschiedener Bedingungen unterschiedliche SQL-Abfragen abzusetzen. Solche Skripte werden blicherweise entweder bei Bedarf per Hand gestartet oder in anderen Programmen eingebettet. Das Innenleben von benutzerdefinierten Funktionen besteht blicherweise auch aus reichlichen PL/SQL-Routinen, selbst wenn diese Funktionen anschlieend nur im Rahmen gewhnlicher Abfragen verwendet werden, so ist deren Erstellung also eigentlich nicht ohne PL/SQL-Programmierung denkbar.

384

PL/SQL-Programmierung

: :

Die Funktionalitt von Datenbanktriggern beinhaltet eigentlich auch fast immer mehr, als die unvernderte Weitergabe genderter Datenstze an irgendwelche Protokolltabellen, so dass bei deren Erstellung blicherweise PL/SQLKommandos zur Anwendung kommen. Letztendlich bleiben dann noch die schon bekannten Objekte der Prozeduren oder Pakete brig, wobei es sich herbei um die PL/SQL-Vertreter schlechthin handelt. Die mgliche Bandbreite reicht von der Erstellungen kleiner Tools, die wiederum vielleicht aus klassischen Programmen heraus gestartet werden, bis hin zur Programmierung ganzer Anwendungen, beispielsweise einer Gehaltsabrechnung.

5.1.2

Blockstruktur

PL/SQL ist wie viele andere Programmiersprachen auch blockorientiert, wobei diese Blockstruktur aus den Schlsselwrtern begin und end gebildet werden, was irgendwie an die Programmiersprache Pascal erinnert. Diese Blcke besitzen in einem PL/SQL-Programm zwei Aufgabenstellungen. Zum einen werden Sie dazu gebraucht, ein solches Programm oder Skript insgesamt zu begrenzen und zum anderen knnen Sie die Blcke dazu benutzen, logisch zusammenhngende Programmteile zu markieren. Neben kosmetischen Grnden gibt es hierfr in der Praxis allerdings auch einen interessanten Anwendungsfall, denn die einzelnen PL/SQL-Blcke knnen verschiedene Fehlerbehandlungsroutinen beinhalten, wobei Sie weitere Informationen hierzu erst spter in diesem Workshop erhalten. Ein PL/SQL-Programm hat damit etwas vereinfacht dargestellt zunchst folgenden schematischen Aufbau:
begin Anweisungen des Block 1 begin Anweisungen des Block 1-1 begin ... end; end; begin ... end; end;

Auerdem gilt, dass alle PL/SQL-Anweisungen, die im brigen formatfrei kodiert werden knnen, mit einem Semikolon (;) abgeschlossen werden. Das gilt, wie Sie ebenfalls dem Schema entnehmen knnen, mit Ausnahme der begin-Anweisung

Einfhrung in PL/SQL

385

auch fr das Schlsselwort end, d.h. neben den einzelnen Anweisungen wird auch ein gesamter Block mit einem Semikolon beendet. Neben einer individuellen Fehlerbehandlung kann jeder PL/SQL-Block ebenfalls einen separaten Deklarationsteil besitzen, mit dessen Hilfe Sie alle bentigten Variablen oder Cursor definieren mssen, so dass sich die Struktur des PL/SQL-Programms bei genauerer Betrachtung ein wenig erweitert (vgl. Listing. 5.1).
declare i integer; begin i := 1; declare ii integer; begin ii:= 2; i := 3; begin ii := 21; end; end; begin i:=33; end; end;
Listing 5.1: Blockstruktur eines PL/SQL-Programms mit verschiedenen Deklarationsteilen

Wie Sie dem Listing entnehmen knnen, wird der jeweilige Deklarationsteile mit Hilfe des Schlsselwortes declare eingeleitet, dem anschlieend eine Aufzhlung aller bentigten Objekte folgt, wobei die Deklaration jedes einzelnen Objekts genau wie eine normale Anweisung wieder mittels eines Semikolons beendet wird. Was Sie dem letzten Beispiel auch entnehmen knnen ist die Sichtbarkeit der einzelnen Variablen in den verschiedenen Programmblcken. Prinzipiell vererbt sich diese Sichtbarkeit entlang der Blockschachtelung von auen nach innen, d.h. die fr den aktuellen Block definierten Variablen knnen auch in allen weiter innenliegenden Blcken verwendet werden. Wenn Sie sich das letzte Beispiel anschauen, dann sehen Sie dort auch schon, wie in PL/SQL die Wertzuweisung zu einer Variablen passiert. Genau wie in einigen anderen Programmiersprachen erfolgt das nicht mit einem einfachen Gleichheitszeichen, sondern durch die Kombination mit einem Doppelpunkt (:). Mehr ber die Deklaration und Verwendung von Variablen und Datentypen erfahren Sie direkt im Anschluss im nchsten Kapitel. Ansonsten ist vielleicht noch wichtig, weil beliebte Fehlerquelle, dass PL/SQL keine leeren Programmblcke vertrgt, d.h. der folgende Block fhrt whrend der Kompilierung zu einem Fehler:

386

PL/SQL-Programmierung

begin end;

Kommentare In Ihren PL/SQL-Programmen knnen Sie an jeder beliebigen Stelle Kommentare einfgen, wobei diese wie blich mit Hilfe spezieller Sonderzeichen markiert werden. Konkret stehen Ihnen hierbei zwei unterschiedliche Varianten zur Verfgen:

Verwenden Sie ein doppeltes Minuszeichen, um den Rest der aktuellen Zeile als Kommentar zu markieren.
-- ich bin ein Kommentar begin -- geht auch hinter einem Befehl

Verwenden Sie die Zeichen /* und *, um den dazwischenliegenden Text als Kommentar zu markieren. Ein solcher Kommentar kann ebenfalls hinter einer beendeten Anweisung beginnen.
/* ------------------------Mehrzeiliger Kommentar ------------------------ */

5.1.3

Datentypen

Bei einem ersten Blick auf die in Oracle vorhandenen bzw. vordefinierten Datentypen kommt man sich vor wie in einem Supermarkt. Da steht schlielich auch nicht nur ein Erdbeerjogurt im Regal, sondern man hat gleich zehn verschiedene zur Auswahl. Doch genau wie bei den Jogurts verhlt es sich auch mit den Datentypen; in beiden Fllen habe ich noch nicht alle vorhandenen Mglichkeiten ausprobiert. Aus diesem Grund finden Sie in diesem Abschnitt zunchst einmal in der Abbildung 5.1 eine bersicht der verfgbaren Typen, wobei ich eine Kurzbeschreibung der aus meiner Sicht wichtigsten Typen in der Tabelle 5.1 zusammengestellt habe. Sofern Sie mehr bzw. weitergehende Informationen bentigen, dann empfehle ich Ihnen das Buch PL/SQL User's Guide and Reference aus der Oracle-Programmdokumentation, in dem Sie nicht nur eine Beschreibung aller vorhandenen Typen, sondern auch ansonsten noch weitergehenden interessante Informationen finden. Wenn Sie ein wenig Programmiererfahrung in einer moderneren Programmiersprache haben, dann werden Ihnen die meisten der in Abbildung 5.1 aufgefhrten Typen bekannt sein, oder Sie knnen sich zumindest vorstellen, welche Daten sich mit ihrer Hilfe speichern lassen. Ansonsten kann ich Sie dahingehend beruhigen, dass auch ich die meisten der hier aufgefhrten Varianten bisher noch nie verwendet habe. Eine bersicht und kurze Beschreibung besonders wichtiger Typen knnen Sie der folgenden Tabelle entnehmen.

Einfhrung in PL/SQL

387

Skalare Typen
binary_integer dec decimal double precision float int integer natural naturaln pls_integer positive positiven real signtype smallint char character long long raw nchar nvarchar2 raw rowid string varchar varchar2 boolean date

Kompositionen
record table varray

Referenzierung
ref cursor ref object_type

Lobs
ffile blob clog nclob

Abbildung 5.1: bersicht der vorhandenen Datentypen Datentyp binary_integer Beschreibung dient zur Speicherung Integerzahlen im Wertebereich on -2147483647 .. 2147483647. Bei der normalen Anwendung knnen Sie statt dieses Datentyps die Werte auch mit number, integer oder pls_integer definieren, jedoch bentigen Sie den Typ binary_integer, wenn Sie in Ihren Programmen noch Tabellen (Datenfelder) vom Typ table verwenden. dient zur Speicherung der Wahrheitswerte true bzw. false, wobei im Ausnahmefall auch ich wei es nicht, also null gespeichert werden kann. Mit diesem Typ werden einzelne Zeichen oder Zeichenketten mit fester Lnge gespeichert, wobei im letzteren Fall eine Lngenvorgabe in der Form char(x) im Wertebereich von 1..32767 erfolgen muss. speichert Datums- und/oder Zeitwerte. Das ist der eigentliche Datentyp, um in Oracle numerische Typen zu definieren. Ohne weitere Vorgeben erzeugen Sie hiermit eine Variable zur Speichern von Fliekommazahlen. Ansonsten haben Sie die Mglichkeit, auch die bentigten Vor- und Nachkommastellen anzugeben, indem Sie die Gre und Genauigkeit der Zahl im Klammern bzw. im Format number(Gre, Genauigkeit) angeben. Bei den anderen numerischen Datentypen (z.B. integer oder smallint) handelt es sich um Spezialflle, die auch alle mit Hilfe einer number-Anweisung deklariert werden knnten, und zum Teil ist die Existenz dieser Spezialtypen auch nur damit zu begrnden, dass die Migration anderer Datenbanken hierdurch vereinfacht wird. dient zur Anlage einer Datenstruktur und ist besonders im Zusammenhang mit Cursorn interessant. Spezielles internes Format zur Aufnahme des internen Datensatzzeigers.

boolean char

date number

record rowid

388

PL/SQL-Programmierung

Datentyp table

Beschreibung dient zur Anlage einer indizierten Tabelle bzw. einem Datenfeld mit variabler Ausdehnung. Als Index wird eine fortlaufende Nummer vom Typ binary_integer verwendet oder das Datenfeld wird als Kollektion verwendet und muss dann mit Hilfe der entsprechenden Methoden selbst dimensioiniert werden. Hiermit knnen Sie Zeichenfolgen mit einer variablen Lnge speichern, wobei Sie die Maximallnge in der Form varchar(x) mit einem Wertebereich von 1..32767 angeben mssen. Hiermit knnen Sie Datenfelder fester Lnge, also mit einer maximalen Anzahl von Elementen definieren.

varchar2

varray

Tabelle 5.1: Beschreibung einiger ausgewhlter Datentypen

Bevor ich nun im nchsten Schritt versuche, die Verwendung der einzelnen Datentypen irgendwie verbal zu beschreiben habe ich mir gedacht, es ist einfacher und ich glaube auch verstndlicher, ich demonstriere die Verwendung an verschiedenen kleinen Beispielen, in dem nichts weiter passiert, als dass die oben beschriebenen Typen verwendet und mit Werten versorgt bzw. abgefragt werden. Benutzen einfacher Datentypen Bei der Verwendung der einfachen Datentypen (vgl. Listing 5.2) ist eigentlich nichts weiter zu beachten, auer vielleicht dass bei der Wertzuweisung bzw. bei Vergleichsoperationen die verwendeten Datentypen zueinander passen sollten. In einigen Fllen klappt auch die gemischte Verendung unterschiedlicher Typen, da Oracle in einem gewissen Umfang die implizite Typkonvertierung beherrscht, wozu ich allerdings spter noch etwas sagen werde.
declare -i x d d1 v b begin -- Verwenden der einfachen Variablen i:=1; x:= 'Hallo'; v:= -33.22; d:= sysdate; d1 := d; b := true; end;
Listing 5.2: Verwenden einfacher Datentypen

Einfache Datentypen integer; varchar2(30); date; date; number(7,2); boolean;

Einfhrung in PL/SQL

389

Strukturen und einfache Felder Die Definition einer Struktur (vgl. Listing 5.3) erfolgt mit Hilfe der Schlsselwrter type und is record. Dazwischen steht der von Ihnen vergebene Name fr die zu definierende Struktur und was danach folgt erinnert irgendwie and die Definition einer Tabelle. Im Prinzip knnen Sie bei der Strukturdefinition wieder weitere Strukturen als Elemente verwenden, wobei die Struktur dann allerdings nicht mehr in einem indizierten Datenfeld benutzt werden kann. Auerdem finden Sie im Listing 5.3 auch zwei Beispiele fr die Definition und Verwendung von indizierten Datenfeldern. Das erste Datenfeld t_ti enthlt als Element eine einfache Zeichenkette mir variabler Lnge, wohingegen die Elemente des zweiten Feldes der definierten Struktur r_xr entsprechen. Damit wir innerhalb des eigentlichen Programmblocks alle diese definierten Typen verwenden knnen, deklarieren wir des weiteren die zugehrigen Variablen v_xr, v_ti und v_pe.
declare -- Definition eines Records ( type r_xr is record persnr varchar2(10), name varchar2(40) ); -- Definition einfacher Datenfelder type t_ti is table of varchar2(10) index by binary_integer; type t_pe is table of r_xr index by binary_integer; -- Einfache Recordvariable v_xr r_xr; -- Variablen fr die Datenfelder definieren v_ti t_ti; v_pe t_pe; begin -- Bestcken des Records v_xr.persnr := '199'; v_xr.name := 'Raymans'; -- Verwenden der einfachen Datenfelder v_ti(22) := v_xr.name; v_pe(33) := v_xr; v_pe(34).persnr := v_xr.persnr; v_pe(34).name := 'Raymans'; end;
Listing 5.3: Beispiel zur Benutzung von Strukturen und einfachen Datenfeldern

390

PL/SQL-Programmierung

Das Schne und Einfache an den indizierten Datenfeldern ist, dass sie ohne Initialisierung und Dimensionierung verwendet werden knnen, d.h. die Wertzuweisung
v_ti(99) := 'Mustermann';

fhrt zum Speichern des vorgegebenen Textes im Element mit der laufenden Nummer bzw. Index 99, ohne dass wir uns zuvor darum kmmern mussten, dass das Datenfeld hinreichend gro ist. Die Verwendung einer Struktur, bzw. der Zugriff der darin enthaltenen Elemente erfolgt in der mittlerweile eigentlich blichen Form, d.h. der Bezeichner der Struktur bzw. die Strukturvariable und der Name des Elements werden gemeinsam verwendet und durch einen Punkt getrennt. Handelt es sich links und rechts vom Gleichheitszeichen um die gleiche Struktur, dann knnen Sie auch eine gesamte Struktur zuweisen oder vergleichen; ansonsten mssen Sie alle entsprechenden Elemente einzeln bertragen oder abprfen. Durch unseren Typ t_pe bzw. der zugehrigen Variable v_pe finden Sie ebenfalls ein Muster, wie eine Struktur innerhalb eines indizierten Datenfelds verwendet werden kann. Varrays und Kollektionen Auch bei den Varrays und Kollektionen handelt es sich im Prinzip um Datenfelder, die innerhalb eines PL/SQL-Programms allerdings anders behandelt werden und die vor allem auch innerhalb der objektorientierten Tabellen verwendet werden knnen. In meinem Beispiel (vgl. Listing 5.4) habe ich zunchst wieder die Struktur r_xr mit zwei Elementen angelegt. Anschlieend definiere ich noch das Varray t_dt, das maximal 22 Datumswerte aufnehmen kann und die Kollektion t_py, die eine beliebige Anzahl von Elementen des Typs r_xr, also unserer Struktur, enthlt. Damit wir im Programmblock wieder mit den erstellten Datentypen arbeiten knnen, deklariere ich zustzlich die entsprechenden Variabeln v_py, v_dt und v_xr.
declare -- Definition eines Records type r_xr is record ( persnr varchar2(10), name varchar2(40) ); -- Definition der Tabellentypen bzw. Datenfelder type t_py is table of r_xr; type t_dt is varray(22) of date; -- Einfache Recordvariable d date; v_xr r_xr; -- Variablen fr die Datenfelder definieren v_py t_py;

Einfhrung in PL/SQL

391

v_dt t_dt; begin -- Verwenden des Varrays v_dt:= t_dt(); v_dt:= t_dt(null, null, null, null); v_dt:= t_dt(sysdate, sysdate+1, sysdate+2, d); d := v_dt(1); v_dt(1) := d; -- Verwenden der Kollektion v_py := t_py(); v_py.extend(1); v_py(v_py.count).name := 'Hugo'; v_xr := v_py(1); end;
Listing 5.4: Beispiele zur Verwendung von Varrays und Kollektionen

Einer der wesentlichen Unterschiede zu den vorhergehenden Beispielen ist, dass die jetzt verwendeten Datenfelder initialisiert bzw. verwaltet werden wollen. Bei den Varrays erfolgt die Initialisierung mit Hilfe einer Konstruktion aus dem zugrundeliegenden Datentyp. Verwechseln sie dabei allerdings nicht die beiden folgenden Anweisungen, die beide als eine Form der Initialisierung verstanden werden knnen:
v_dt:= t_dt(); v_dt:= t_dt(null, null, null, null);

Die erste Anweisung fhrt nmlich dazu, dass das Datenfeld anschlieend leer ist, also keine Elemente mehr enthlt und damit im Programm auch nicht zum Speichern konkreter Werte benutzt werden kann. Im Unterschied dazu verschafft die zweite Anweisung im Varray vier leere Pltze zum Speichern eines beliebigen Datumswertes. In beiden Fllen wird der definierte Datentyp t_dt als Konstruktor fr die typkonforme Wertzuweisung benutzt. Ist so ein Varray erst einmal initialisiert bzw. dimensioniert, dann knnen Sie es wie ein indiziertes Datenfeld verwenden, wobei der grte verwendbare Index von der konkreten Initialisierung und der entsprechend der Deklaration maximalen Gre abhngt. Die aktuelle Gre eines Varrays knnen Sie brigens mit Hilfe der Methode count abfragen, die Ihnen die aktuelle Gre des Datenfeldes liefert:
if v_dt.count = 4 then ... i := v_dt.count

Neben dem Varray finden Sie in dem Beispiel 5.4 auch ein Muster fr die Anwendung einer Kollektion. Konkret geht es um den Typ t_py bzw. die zugehrige Variable v_py, mit denen Sie in Ihrem Programm ein beliebiges Datenfeld mit der definierten r_xr-Struktur benutzen knnen. Genau wie beim Varray und im Unter-

392

PL/SQL-Programmierung

schied zu den indizierten Datenfeldern mssen Sie jetzt allerdings wieder ein Stck Extraarbeit leisten und die Verwaltung des Feldes bernehmen. Diese beginnt genau wie beim Varray mit der Initialisierung des Feldes, beispielsweise durch Zuweisung eines leeren Feldes, das wiederum mit Hilfe des zugehrigen Typs als Konstruktor gebildet wird.
v_py := t_py()

Anschlieend ist unsere Kollektion zwar leer, aber gebrauchsfertig. Um nun konkret einen Datensatz in der Kollektion speichern zu knnen, mssen Sie dafr zunchst den bentigten Platz schaffen, wobei Oracle zur Verwaltung der Kollektionen eine Reihe von Methoden zur Verfgung stellt. Die Methode zur Aufnahme neuer Elemente in die Kollektion heit extend und wird im einfachsten Fall einfach mit der Anzahl der neuen Elemente verwendet.
v_py.extend(1); v_py.extend(5, 2);

Die erste Anweisung erweitert die Kollektion um ein leeres Element, wohingegen die zweite fnf Kopien des zweiten Elements ans Ende anfgt. Auch fr die Kollektionen gilt, das die sonstige Anwendung den indizierten Datenfeldern eigentlich sehr hnlich ist, d.h. Sie knnen beispielsweise auch wieder mit Hilfe einer Indexnummer direkt auf ein spezielles Element zugreifen. Eine Beschreibung der insgesamt vorhandenen Methoden exists, count, limit, first, last, prior, next, extend, trim und delete finden Sie in der PL/SQL-Dokumentation PL/SQL User's Guide and Reference. Gehen Sie dort in das Kapitel Using Collection Methods bzw. den dortigen Abschnitt Collection and Records. Ausdrcke Vor ein paar Seiten hatte ich die Wertzuweisung so nach dem Motto links die Variable und rechts etwas passendes und dazwischen Doppelpunkt und Gleichheitszeichen in einem Nebensatz erwhnt und damit die einfachste Form eines Ausdrucks beschrieben, der nur aus einer Konstanten oder Variablen besteht. In der Praxis knnen rechts vom Gleichheitszeichen natrlich komplexere Konstruktionen stehen, die blicherweise als Ausdruck oder Formel bezeichnet werden. Ein solcher Ausdruck enthlt Variablen, Konstante, Funktionen, die mit Hilfe geeigneter Operatoren verknpft werden, so dass das Ergebnis dieser gesamten Verknpfung der links vom Doppelpunkt spezifizierten Variablen zugewiesen wird. Das Schne an der hier verwendeten Schreibweise ist, dass Sie beispielsweise innerhalb eines Seminars bei vielen Teilnehmern weniger Stirnrunzeln hervorruft, denn folgender Ausdruck x=x+1 ist, und soviel Schulmathematik kennt wohl jeder, eben nicht gleich. Nicht unbedingt einleuchtend ist, dass hiermit ja auch gemeint ist, das das Ergebnis der Formel x+1 der alten Variablen x wieder zugewiesen werden soll. Gut, dass wir in Oracle daher x:=x+1 schreiben und damit deutlich machen, dass wir der in der Formel verwendeten Variablen auch das Ergebnis wieder speichern mchten.

Einfhrung in PL/SQL

393

Achten Sie bei komplexeren Formeln darauf, dass alle beteiligten Variabeln, Konstanten und Funktionen einen kompatiblen Datentyp besitzen, damit nicht die implizite Konvertierungsmaschinerie in Gang gesetzt wird, deren Ergebnis manchmal passen, manchmal aber auch dubios sein knnen. Ansonsten haben Sie bei der Verknpfungen der am Ausdruck beteiligten Elemente die in der Tabelle 5.2 beschriebenen Operatoren zur Auswahl.
Operator +Beschreibung fhrt zur Addition bzw. Subtraktion zweier numerischer Werte. Das einzelne vorangestellte Minuszeichen fhrt zur Vorzeichenumkehr x := - (2 + 3) bzw. kennzeichnet eine negative Zahl x := 3 * -2. Mit Hilfe dieser Operatoren knnen Sie zwei numerische Werte multiplizieren bzw. dividieren. Dies ist ein Operator, mit dem Sie zwei Zeichenketten aneinanderhngen knnen.

*/ ||

Tabelle 5.2: Verknpfungsoperatoren fr Ausdrcke

Bei gleichwertigen Operatoren (z.B. nur Additionen) wird die Berechnung eines Ausdrucks von rechts nach links durchgefhrt. Ansonsten richtet sich die Berechnung nach der Rangfolge eines Operators, wobei auch in Oracle grundstzlich Punkt vor Strichrechnung gilt. Eine gewisse Ausnahme dieser Regel bildet das Minuszeichen in der Verwendung als Negationsoperator a := b * -c, denn in dem Fall hat es die hchste Prioritt. Ist diese normale Reihenfolge nicht sinnvoll, dann knnen Sie diese mit Hilfe von gewhnlichen Klammern beliebig verndern, wobei in Fall von geschachtelten Klammern, die innersten zuerst ausgewertet werden. Initialisierung und not null Im Rahmen der letzten Beispiele haben Sie Situationen kennen gelernt, bei denen besondere Datentypen erst nach einer durchgefhrten Initialisierung verwendbar waren. Diese Initialisierung erfolgte mit Hilfe einer geeigneten Wertzuweisung und ist streng genommen nicht nur eine Anforderung komplizierter Datentypen, sondern tut eigentlich allen definierten Variabeln gut. Standardmig enthalten nmlich auch die einfachen Variabeln beim Programmstart den besonderen Wert null, also nichts, was zu Problemen bei der Verwendung in einem Ausdruck fhren kann. Betrachten Sie hierzu das folgende kleine Beispiel:
declare i integer; b integer; begin b := 2 + i; end;

Das Problem an dem markierten Ausdruck ist, dass die Variable b nach der Berechnung nicht den Wert 2, sondern null enthlt, weil in dem Berechnungsausdruck eine nicht initialisierte Variable enthalten war. Wegen dieser mglichen Probleme sollte man sich in einem Programm entweder fr einen speziellen Initialisierungs-

394

PL/SQL-Programmierung

teil entscheiden, oder diese Aufgabe schon bei der Deklaration der Variablen erledigen. Hierfr gibt es im PL/SQL-Sprachumfang zwei verschiedene Mglichkeiten, deren Bewertung ich mal wieder der Kategorie Geschmacksache zuordnen wrde. Zum einen knnen Sie der Variablendeklaration eine Art Wertzuweisung anhngen, so dass die Variablen beim Starten des Programms bzw. des zugehrigen Blocks schon die dort spezifizierten Werte enthalten.
declare i x d d1 v b integer := 1; varchar2(30) := 'Hallo'; date := sysdate; date := d+1; number(7,2) := -33.22; boolean := true;

Zum anderen besteht ebenfalls die Mglichkeit, die Initialisierung mit Hilfe des Schlsselworts default vorzunehmen, so dass das Ganze genauso funktioniert und nur etwas anders aussieht:
declare i x d d1 v b integer default 1; varchar2(30) default 'Hallo'; date default sysdate; date default d+1; number(7,2) default -33.22; boolean default true;

Wofr Sie sich auch immer entscheiden mgen, besonders interessant ist die in dem Beispiel markierte Stelle, denn die zeigt Ihnen, dass Sie im Rahmen der Initialisierung auch wieder Berechnungen, also komplexere Ausdrcke einsetzen knnen. Hierbei mssen Sie allerdings ein wenig auf die Reihenfolge der im Ausdruck verwendeten Variablen achten, denn erst am Ende des Deklarationsteils sind alle definierten Objekte bekannt, d.h. erst dann knnten alle denkbaren Verknpfungen aufgelst werden. Auch kompliziertere Datentypen wie Strukturen, Varrays oder Kollektionen knnen schon whrend der Deklaration mit Werten ausgestattet werden. Bei Strukturen passiert das in der Form, dass Strukturdefinition und nicht die eigentliche Variable initialisiert wird.
declare type r_xr is record ( persnr varchar2(10) := '475837', name varchar2(40) := 'Raymans'); v_xr r_xr;

Wie Sie dem Beispiel entnehmen knnen, erfolgt die Initialisierung einer Struktur schon whrend der Typdeklaration, so dass auch die zugehrige Variable v_xr automatisch die definierten Standardwerte in ihren Elementen enthlt. Betrachten wir nun noch, wie die Initialisierung bei den Varrays und Kollektionen funktioniert.

Einfhrung in PL/SQL

395

declare type t_py is table of r_xr; type t_dt is varray(22) of date; v_py t_py := t_py(v_xr, null); v_dt t_dt := t_dt(null, null, null, null);

Beginnen wir auch diesmal wieder mit der Betrachtung des Varrays. Genau wie bei einer der im Beispiel 5.4 verwendeten Initialisierungsvariante dimensionieren wir das Datenfeld v_dt mit insgesamt vier leeren Elementen. Auch die Erstausstattung der Kollektion erfolgt wieder mit Hilfe einer Konstruktion aus dem Datentyp. Im Unterschied zu dem Beispiel 5.4 legen wir diesmal allerdings keine leere Kollektion an, sondern statten diese mit zwei Elementen aus. Das erste Element entspricht dabei einer Kopie der Strukturvariablen v_xr und das zweite Element der Kollektion ist leer. Damit wren wir in Bezug auf die Initialisierung eigentlich fertig, jedoch beinhaltet die zu diesem Abschnitt gehrende berschrift noch den Hinweis auf eine weitere Aufgabenstellung, die sich allerdings kurz und knapp oder schnell und schmerzlos beschreiben lsst. Genau wie bei der Anlage einer Datenbanktabelle, wo Sie bei jedem Datenfeld die Fhigkeit zur Aufnahme eines null-Wertes durch eine besondere Klausel verhindern konnten, so besteht auch innerhalb eines PL/SQL-Programms eine entsprechende Verfahrensweise, um den Variablen die Aufnahme dieses Wertes zu verbieten. Wie Sie dem folgenden Beispiel entnehmen knnen, geschieht das brigens wieder mit Hilfe der gleichen not null-Klausel, wobei diese auch direkt wieder hinter dem spezifizierten Datentype angeordnet wird.
declare i integer not null default 1; x varchar2(30) not null := 'Hallo';

Typableitung In einem Programm werden meistens Daten verarbeitet, die in der Datenbank mit Hilfe irgendwelcher Tabellen gespeichert werden. Auch wenn sich dieser Satz zunchst noch so anhrt, als wrde ich sagen Wasser ist nass, so ergibt sich daraus doch eine entscheidende Konsequenz. Werden diese Daten bzw. die zugehrigen Felder whrend der Verarbeitung nmlich in entsprechenden Variablen oder Strukturen zwischengespeichert, so entsteht schon auf Feldebene eine enge Abhngigkeit zwischen dem Datenhaushalt und den zugehrigen Anwendungsprogrammen. Felder knnen sich im Laufe der Zeit ndern, indem sie beispielsweise lnger werden oder in einen anderen Datentyp berfhrt werden, so dass in dem Fall auch alle zugehrigen PL/SQL-Programme berprfen mssten. Natrlich sind Programme meistens irgendwie an die zugehrigen Daten gebunden und dennoch ist es lstig und eigentlich unntig, ber Programmnderungen nachzudenken, nur weil ein Textfeld um zehn Stellen verlngert wurde.

396

PL/SQL-Programmierung

Damit so etwas nicht passiert, knnen Sie die im Programm verwendeten Datentypen aus den zugehrigen Daten ableiten, d.h. Sie beziehen sich bei der Anlage des Feldes auf die entsprechende Tabelle bzw. das dort enthaltene Feld und sagen dem PL/SQL-Programm, dass Ihre Variable den gleichen Typ besitzen soll. Wird der morgen gendert bzw. erweitert, dann funktioniert auch Ihr Programm ab morgen automatisch in entsprechender Weise.
declare ge gehalt.gehalt%type; ps personalien%rowtype;

Die Zauberwrter fr diese Technik heien type und rowtype und werden wie in dem eben gezeigten Beispiel zusammen mit einem Prozentzeichen (%) angewendet. Dabei mssen Sie die type-Klausel verwenden, wenn Sie eine einfache Variable entsprechend eines in der Datenbank vorhandenen Feldes definieren mchten, d.h. Sie mssen hierbei neben dem konkreten Feld auch noch die zugehrige Tabelle vorgeben. Im Gegensatz dazu hilft die rowtype-Klausel bei der Anlage von Strukturvariablen, die beispielsweise dem Aufbau einer in der Datenbank vorhandenen Tabelle entsprechen sollen und wird daher auch nur zusammen mit einem Tabellennamen verwendet. Implizite Konvertierung Immer wenn man innerhalb von Ausdrcken mehrere Felder oder Variablen miteinander verknpft dann luft man Gefahr, dass die vorhandene implizite Datentypkonvertierung zuschlgt. Beim bisherigen Lesen dieses Buches haben Sie sicherlich schon gemerkt, dass ich nicht unbedingt ein Freund dieser automatischen Wandelung bin. Sicherlich ist das Wandeln bzw. Anpassen des Datentyps kein Problem, wenn die beteiligten Variablen zumindest der gleichen Typenklasse entspringen oder die Umwandlung in einen greren, bergeordneten Typ erfolgt. Ab es wird auch an Stellen umgeformt, wo das Ergebnis manchmal dubios ist, beispielsweise von Zeichenketten in Datumswerte oder umgekehrt. Die insgesamt mglichen implizierten Konvertierungen habe ich Ihnen einmal mit Hilfe der Oracle-Dokumentation in der Tabelle 5.3 dargestellt, wobei ich die Stellen fett markiert habe, wo die implizierte Konvertierung keine Probleme bereitet; an den anderen gekennzeichneten Stellen sollten Sie aber zumindest vorsichtig sein.
VARCHAR2 Ja Ja Ja Ja Ja Ja X Ja Ja Ja

NUMBER

BIN_INT

PLS_INT

BIN_INT CHAR DATE LONG NUMBER

X Ja

Ja X Ja Ja Ja X

Ja Ja Ja X Ja

Ja Ja

Ja Ja

Ja

Ja

ROWID

LONG

CHAR

DATE

RAW

Einfhrung in PL/SQL

397

PLS_INT RAW ROWID VARCHAR2

Ja

Ja Ja Ja

Ja Ja

Ja

X X X

Ja

Ja

Ja

Ja

Ja

Ja

Ja

Ja

Tabelle 5.3: bersicht der mglichen impliziten Datenkonvertierung

Wie schon gesagt, sollten Sie an den Stellen, wo kein fettes Ja steht ein wenig wachsam sein, wohingegen Sie in allen anderen Fllen explizit, also mit Hilfe spezieller Funktionen, konvertieren mssen. Falls Sie sich nun fragen, warum ich diesen automatischen Wandelmechanismus nicht einfach nur als Feature hinstelle, so mchte ich darauf kurz antworten. Wenn Datentypen eigentlich nicht zueinander passen (z.B. Texte und Zahlen oder Texte und Datumswerte), dann erfolgt eine implizite Umwandlung auf der Basis von Einstellungen und Regeln. Sowohl Einstellung als auch Regeln knnen sich allerdings ndern, so dass Ihr Programm vielleicht von heute auf morgen anders als sonst reagiert. So knnen Sie beispielsweise mit Hilfe der Anweisung
alter session set nls_date_format = 'DD.MM.YYYY';

die standardmige Datumsaufbereitung fr Ihre Session einstellen. Ist die so wie in dem obigen Beispiel gesetzt, dann funktioniert das folgende Programm einwandfrei:
declare d date; begin d:= '22.11.2000'; end;

Aber eben nur dann, d.h. bei einer anderen Einstellung wie zum Beispiel dem Standardwert fhrt die Ausfhrung des Skripts zu einem Fehler. hnliches gilt fr die zugrundeliegenden Regeln. Diese knnen sich theoretisch schon innerhalb eines Mini-Updates ndern und so in bestimmten Grenzfllen bei der impliziten Konvertierung zu anderen Ergebnissen fhren. Der dritte Grund warum ich so skeptisch bin ist, dass der fahrlssige Umgang mit Datentypen auch eine beliebte und schwierig zu findende Fehlerquelle ist. Werden whrend einer Berechnung bestimmte Zwischenergebnisse aus Versehen in einen Integertyp konvertiert, dann sind am Ende alle Nachkommastellen weg.

VARCHAR2 Ja Ja Ja X

NUMBER

BIN_INT

PLS_INT

ROWID

LONG

CHAR

DATE

RAW

398

PL/SQL-Programmierung

5.1.4

Funktionen

Eine Programmiersprache ohne Funktionen kann ich mir gar nicht mehr vorstellen, wobei die verschiedenen Funktionen in Oracle nicht nur innerhalb eines PL/ SQL-Programms, sondern auch fr die ganz normalen SQL-Abfragen verfgbar sind. Allerdings bertrifft Oracle das eine oder andere bzw. die meisten anderen Datenbanksysteme dahingehend, dass Sie in der Lage sind, auch selbst Funktionen zu erstellen, die anschlieend auch innerhalb der Programmierung oder bei der Abfrageerstellung eingesetzt werden knnen. Wie eigene Funktionen erstellt werden knnen ist in diesem Kapitel nicht das primre Thema, sondern ich mchte Ihnen hier im Wesentlichen eine bersicht der standardmig verfgbaren Miniprogramme geben. Dennoch finden Sie in diesem Buch auch hierber einige Informationen. Da wre zunchst einmal die Beschreibung der einzelnen Schema-Objekte im Kapitel 2, wo sich ein separates Kapitel mit den Funktionen beschftigt. Auerdem finden Sie auch weiter unten bei den Anwendungsbeispielen weitere Anmerkungen zur Funktionserstellung. Zur generellen Verwendung einer Funktion mchte ich eigentlich nicht viel sagen. Wie in allen Programmiersprachen werden die Funktion mit Hilfe Ihres Namens aufgerufen und erhalten dabei keine oder mehrere Parameter, die in Klammern und durch Komma getrennt und in der richtigen Reihenfolge zu bergeben sind. Als Ergebnis bekommt man genau einen Wert in Form eines bestimmten Datentyps zurck und genau wegen dieser Verhaltensweisen knnen die Funktionen so elegant und sogar beliebig geschachtelt in Ausdrcken verwendet werden. Oftmals werden Funktionen bei der Dokumentation einer Programmiersprache in Gruppen eingeteilt. So finden man dort beispielsweise die Gruppe der numerischen Funktionen, die sich dadurch auszeichnen, dass die Funktion als Ergebnis einen numerischen Wert zurckliefert und vielleicht sogar eine Zahl als Parameter erwartet. Auf ganz hnliche Weise entstehen so auch die Gruppen der String- oder Datumsfunktionen. Auf der anderen Seite gibt es Funktionen, die man nicht so gerne der einen oder anderen Gruppe zuordnen mchte bzw. gar nicht zuordnen kann. Das sind beispielsweise Funktionen, die zur Datumskonvertierung benutzt werden oder spezielle Systemfunktionen. Ich werde eine solche Gruppierung im Folgenden auch durchfhren, dabei allerdings nur die wichtigsten Funktionen in diesem Workshop beschreiben. Dabei beginne ich ab Tabelle 5.4 mit der bersicht numerischer Funktionen. In jedem Fall finden Sie da, wo es sich lohnt hinter den Tabellen noch die eine oder andere Ergnzung oder ein vertiefendes Beispiel. Numerische Funktionen Die Gruppe von Funktionen liefert als Ergebnis eine Zahl und erwartet als Parameter ebenfalls numerische Werte.
Funktion abs Beschreibung ermittelt den absoluten Betrag des bergebenen Wertes, d.h. mit anderen Worten erhalten Sie als Ergebnis den bergebenen Wert mit positivem Vorzeichen.

Einfhrung in PL/SQL

399

Funktion ceil

Beschreibung Diese Funktion liefert die kleinste ganze Zahl, die gleich oder grer dem bergebenen Wert ist. Der Ausdruck ceil(14.3) liefert als Ergebnis also 15, wohingegen ceil(-14.3) zwar immer noch die nchstgrere ganze Zahl und deshalb 14 liefert. Die ceil-Funktion eignet sich unter anderem prima zum Runden. Mchten Sie einen berechneten Betrag n beispielsweise auf volle 25,- _ runden, dann knnen Sie das folgendermaen realisieren: ceil(n / 25) * 25. Hiermit berechnen Sie fr den bergebenen Wert die grte ganze Zahl, die kleiner oder gleich diesem Wert ist. Damit ergibt der Ausdruck floor(14.3) jetzt 14 und floor(-14.3) bewegt sich jetzt in die andere Richtung und liefert 15. Die sogenannte Modulo-Funktion berechnet den Rest einer ganzzahligen Division, d.h. die Funktion erhlt diesmal zwei Werte. Konkret liefert mod(m, n) den Rest der Ganzzahldivision von m durch n, z.B. gilt: mod (11, 3) = 2. Wenn Sie also einmal den Rest einer Division von m durch n bentigen, dann knnen Sie anstelle der Formel m n * (floor(m / n)) auf einfach mod benutzen. Wenn Sie bei den Operatoren einen Potenzoperator vermisst haben, dann liegt das daran, dass es in PL/SQL hierfr eine Funktion gibt. Die power-Funktion erwartet zwei numerische Werte und potenziert den ersten mit dem zweiten bergebenen Parameter, z.B. liefert power(3, 2) als Ergebnis die Zahl neun. Mit Hilfe der round-Funktion knnen Sie den bergebenen numerischen Wert runden. Die Funktion erwartet normalerweise zwei Parameter, wobei der erste den zu rundenden Wert und der zweite die zu rundende Stelle, also quasi die verbleibenden Nachkommastellen, vorgibt. Sofern Sie den zweiten Parameter weglassen, dann nimmt Oracle hierfr automatisch den Wert 0 an, d.h. es wird auf die erste Stelle vor dem Komma gerundet. Sie knnen mit dieser Funktion brigens auch runden, indem Sie bei der Genauigkeit negative Zahlen verwenden, was zur Rundung vor dem Komma fhrt. Vorzeichenfunktion, die als Ergebnis 0, 1 oder 1 liefert, wenn der bergebene Wert 0, positiv oder negativ ist. berechnet die Quadratwurzel fr den bergebenen Wert. Falls es bei Ihnen auch schon so lange her ist: Eine beliebige Wurzel knnen Sie berechnen, indem Sie zusammen mit der power-Funktion anstelle der Wurzel den Kehrwert als Exponent verwenden. Falls sich das jetzt wie die automatische bersetzung aus dem Chinesischen anhrte, so mchte ich es noch einmal mit einem Beispiel versuchen. Die vierte Wurzel aus 16 berechnen Sie folgendermaen: power(16, 1/4). Die trunc-Funktion scheidet dem bergebenen Wert die Nachkommastellen ab. Sofern nicht alle abgeschnitten werden sollen, dann knnen Sie die Zahl der brigbleibenden als zweiten Parameter vorgeben.

floor

mod

power

round

sign sqrt

trunc

Tabelle 5.4: Tabelle 5.4: bersicht wichtiger vordefinierter Funktionen

Funktionen fr Zeichenketten Diese Funktionsgruppe verwendet als wesentliches Argument eine Zeichenfolge und liefert im Normalfall auch einen Text zurck. Auch hier gilt das keine Regel ohne Ausnahme ist, weshalb manche Funktion eine Zahl als Argument erhlt.

400

PL/SQL-Programmierung

Funktion chr concat initcap

Beschreibung liefert das dem bergebenen Wert entsprechende Zeichen entsprechend dem fr die Datenbank eingestellten Zeichensatz. Falls Sie den Operator || nicht mgen, dann knnen Sie zwei Zeichenfolgen auch mit dieser Funktion aneinanderhngen. Diese Funktion versucht den bergebenen String nach einfachem Strickmuster in Gro-/Kleinschreibweise umzuwandeln. Allerdings ist das Ergebnis aus meiner Sicht meistens zweifelhaft, denn die Funktion liefert beim Aufruf initcap('herman van veen') als Ergebnis Herman Van Veen zurck. Mit dieser Funktion wandeln Sie die bergebene Zeichenfolge in Kleinbuchstaben um. Die lpad-Funktion erwartet insgesamt drei Parameter, von denen der erste und letzte Zeichenketten und der mittlere eine Ganzzahl ist. Konkret geht es darum, den als ersten Parameter bergebenen Text auf die im zweiten Parameter spezifizierte Lnge zu bringen. Dazu wird der als dritte Parameter spezifizierte Text, der beim Weglassen als einzelnes Leerzeichen gedeutet wird, so lange aneinanderhngt, bis diese Kette zusammen mit der bergebenen Zeichenfolge die gewnschte Textlnge erreicht. Diese Kette wird anschlieend vor der bergebenen Zeichenfolge gestellt und zusammen mit dieser zurckgegeben. Diese Funktion erwartet blicherweise auch zwei Zeichenfolgen, wobei beim Fehlen der zweiten ein einzelnes Leerzeichen angenommen wird. Ansonsten wird der linke Teil der im ersten Parameter bergeben Zeichenfolge abgeschnitten, so lange die Zeichen dem zweiten Parameter entsprechen. In der Praxis wird die ltrim-Funktion nur zusammen mit einer Zeichenkette verwendet, bei der vorangestellte Leerzeichen abgeschnitten werden sollen. Mit Hilfe dieser Funktion knnen Sie fr eine bergebene Zeichenfolge eine Suchen- und Ersetzen-Funktion ausfhren. Die Funktion bentigt also insgesamt drei Textparameter. Spezifizieren Sie als Erstes die zu durchsuchende Zeichenkette, danach den Such- und als Letztes den Ersetzungsbegriff. Konkret wird aus replace(JACK AND JUE,J,B) somit BLACK AND BLUE. funktioniert analog zur lpad, nur dass sich das Geschehen jetzt auf der rechten Seite der zu verlngernden Zeichenkette abspielt. Genau wie bei ltrim wird die bergebene Zeichenfolge gekrzt, diesmal allerdings auf der rechten Seite. Meistens wird mit dieser Funktion anhngende Leerzeichen abgeschnitten. Mit dieser Funktion knnen Sie aus einer Zeichenfolge eine beliebige andere Zeichenkette herausschneiden, wobei Sie die Anfangsposition und die Schnittlnge beliebig vorgeben knnen. Konkret besitzt die Funktion also einen ersten Textund ein bis zwei numerische Parameter. Dabei gibt der erste Parameter die Zeichenfolge vor, aus der ein gewnschter Text herausgeschnitten werden soll. Der zweite Parameter bestimmt die Anfangsposition und der letzte bergebene Wert bestimmt die Anzahl der herauszuschneidenden Zeichen. Sofern Sie ihn weglassen, schneidet die Funktion immer von der Anfangsposition bis zum Ende des Textes aus. Sofern Sie als zweiten Parameter eine negative Zahl verwenden, wird die Anfangsposition vom rechten Ende an ermittelt.

lower lpad

ltrim

replace

rpad rtrim

substr

Einfhrung in PL/SQL

401

Funktion translate

Beschreibung Mit dieser Funktion knnen Sie einen Text zeichenweise bersetzen. Hierzu werden drei Parameter bentigt. Als Erstes mssen Sie die zu bersetzende Zeichenfolge vorgeben und mit Hilfe der beiden nchsten Textparameter legen Sie die zu bersetzenden Zeichen in korrespondierender Reihenfolge fest, d.h. das n-te Zeichen im Parameter 2 wird durch das entsprechende Zeichen im dritten Parameter ersetzt. Betrachten wir zur Verdeutlichung das folgende Beispiel translate('Raymans','am','12'), indem in der bergebenen Zeichenfolge jedes a in eine 1 und jedes y in eine 2 bersetzt werden soll. Alle anderen Zeichen kommen nicht in den bersetzungstabellen vor und bleiben daher unverndert, so dass dieses Beispiel den Text R1m21ns als Ergebnis liefert. wandelt hnlich wie die lower-Funktion die bergebene Zeichenkette in Grobuchstaben um.

upper

Tabelle 5.5: bersicht wichtiger Zeichenkettenfunktionen

Zeichenkettenfunktionen mit numerischer Rckgabe Diese jetzt folgende Funktionsgruppe erwartet als wesentliches Argument wieder eine Zeichenfolge, liefert jedoch ein numerisches Ergebnis zurck.
Funktion ascii Beschreibung liefert fr ein bergebenes Zeichen die Position, an der es in dem Zeichensatz der Datenbank kodiert ist. Ist ascii-Funktion ist also das Gegenstck zur chrFunktion. Diese Funktion wird zum Finden eines Zeichens oder eines Textes in einer anderen Zeichenfolge verwendet und blicherweise mit drei Parametern verwendet. Der dritte Parameter legt dabei fest, ab welcher Stelle die Funktion mit der Suche beginnen soll. Der Ausdruck instr(Raymans, a, 1) liefert als Ergebnis also den Wert 2, wohingegen man bei instr(Raymans, a, 6) als Ergebnis den Wert 0 erhlt, da der gesuchte Buchstabe nach der sechsten Stelle nicht mehr auftaucht. Mit dieser Funktion knnen Sie die Lnge, als die Anzahl der vorhandenen Zeichen, des bergebenen Textausdrucks ermitteln. Das ist eine ganz besondere Funktion, deren Verwendung ich im Anschluss an diese Tabelle noch einmal zeigen werde. Gewhnliche Sortieranweisungen fhren immer zur binren Sortierung der Daten, d.h. die Daten werden entsprechend der Positionen der Zeichen im Zeichensatz sortiert. Das fhrt vor allem bei uns zu Problemen, wenn nach bestimmten Feldern (z.B. Name) sortiert wird und diese Felder Sonderzeichen bzw. Umlaute enthalten knnen, denn die Sonderzeichen bzw. Umlaute werden bei der binren Sortierung ans Ende des Alphabets gerckt. Mit Hilfe dieser Funktion knnen Sie diesem Problem entgegnen und einen Begriff erzeugen, der sich lexikalisch sortieren lsst.

instr

length nlssort

Tabelle 5.6: Wichtige Funktionen fr Zeichenfolgen mit numerischem Ergebnis

402

PL/SQL-Programmierung

Ein besonderes Augenmerk mchte ich noch einmal auf die Funktion nlssort lenken, mit der Sie, wie gesagt, eine Zeichenfolge in ein lexikalisches quivalent berfhren knnen. Gerade wir haben wegen unserer Sonderzeichen ein Problem, wenn es darum geht Datenstze nach Feldern mit Umlauten zu sortieren oder zu selektieren. So fhrt die Auswahl
where name between 'A' and 'Z'

beispielsweise nicht zur Anzeige des Namens glo oder tztrk, da diese wegen des Umlauts als ersten Buchstaben in der binren Sortierreihenfolge erst hinter Z folgen. Gleiches gilt im brigen auch fr die Sortierung, d.h. Sie wrden den Namen nderson nicht am Anfang, sondern erst ganz am Ende der Liste finden. Mit Hilfe der nlssort-Funktion knnen Sie dieses Dilemma lsen, indem Sie die entsprechenden Strings geeigent umformatieren, so dass anschlieend sowohl eine korrekte Selektion wie auch eine ordentliche Sortierung mglich ist. Konkret bentigt die Funktion hierzu neben der umzuformatierenden Zeichenfolge auch die Angabe des dabei zu verwendenden Regelwerkes, das bei uns quasi konstant in der Form
'NLS_SORT = German'

verwendet werden kann. Das nun folgende Beispiel (vgl. Listing 5.5) zeigt Ihnen die konkrete Anwendung.
SQLWKS> select name, nlssort(name, 'NLS_SORT = German') 2> from personalien 3> where nlssort(name, 'NLS_SORT = German') 4> between nlssort('A','NLS_SORT = German') 5> and nlssort('Z', 'NLS_SORT = German') 6> order by nlssort(name, 'NLS_SORT = German') 7> NAME NLSSORT(NAME,'NLS_SORT=GERMAN' Btzing,Brbel 19146E873C553219146419284B0002 Beckmann,Yonne 19281E4650145555825A5555280000 Bruckner,Yonne 1964731E46552864825A5555280002 Calvo,Ulrike 1E144B785A734B643C462800020100 ... glo, Heinz 73324B5A0137283C5587000A010101 Underglo, Heinz 7355232864324B5A0137283C558700 Voltair,Samuel 785A4B6E143C6469145073284B0002 Voltair,Samuel 785A4B6E143C6469145073284B0002 Voltair,Samuel 785A4B6E143C6469145073284B0002 25 rows selected.
Listing 5.5: Verwenden der nlssort-Funktion

Einfhrung in PL/SQL

403

Ein bisschen Arbeit ist da natrlich schon, denn Sie mssen alle verwendeten Felder und Texte mit Hilfe der Funktion umwandeln und das nicht nur einmal, sondern mehrfach an unterschiedlichen Stellen. Aus diesem Grund bestnde gerade fr so ein Namensfeld natrlich auch die Mglichkeit, das nlssort-Ergebnis mit Hilfe einer zustzlichen Spalte in der Tabelle zu speichern und diese bei einer Namensnderung mit Hilfe eines Triggers zu aktualisieren. In dem Fall wrden nicht nur zwei nlssort-Anweisungen wegfallen, sondern das System knnte bei der nls-Namenssuche wieder einen Index verwenden, sofern fr diese Spalte einer angelegt wurde. In dem Fall mssten Sie die Tabelle mit einem neuen Feld (z.B. nls_name) erweitern, dass mindestens viermal so lang wie das zugehrige Klartextfeld sein muss. Die Erweiterung der Tabelle Personalien in unserer Musterdatenbank knnte beispielsweise folgendermaen aussehen:
alter table personalien add nls_name varchar2(300); update personalien set nls_name = nlssort(name, 'NLS_SORT = German');

Anschlieend knnen Sie dann die im Beispiel 5.5 gezeigte Abfrage folgendermaen verndern.
select name from personalien where nls_name between nlssort('A','NLS_SORT = German') and nlssort('Z','NLS_SORT = German') order by nls_name

Datumsfunktionen In dieser Gruppe finden Sie vor allem Funktionen, die ein Datum als Argument erwarten und als Ergebnis wiederum ein Datum oder einen Teil daraus zurckgeben. Ohne spezielle Funktionen knnen Sie mit Datumswerten nur wenige Operationen Berechnungen direkt ausfhren. Zum einen knnen Sie zwei Datumswerte miteinander vergleichen, und das innerhalb einer Auswahl- oder Konditionalbedingung verwenden. Zum anderen knnen Sie eine ganze Zahl zu einem Datum addieren bzw. von diesem abziehen, wobei diese Zahl dabei als eine Anzahl von Tagen interpretiert wird, so dass als Ergebnis das entsprechende neue Datum dabei herauskommt. Auerdem knnen Sie zwei Datumswerte voneinander abziehen, wobei Sie als Ergebnis in dem Fall die Anzahl der dazwischenliegenden Tagen erhalten. Je nachdem, ob Sie dabei das jngere vom lteren Datum abziehen oder umgekehrt, ist das Ergebnis positiv bzw. negativ. Weitergehende Berechnungen sind auch mglich, bedrfen jedoch den Einsatz spezieller Funktionen, fr die Sie in der nun folgenden Tabelle 5.7 eine bersicht finden.

404

PL/SQL-Programmierung

Funktion add_months

Beschreibung Diese Funktion erwartet zwei Parameter. Beim ersten handelt es sich um einen Datumswert und beim zweiten um eine ganze Zahl. Als Ergebnis liefert sie wiederum ein Datum, das einer der Zahl entsprechenden Anzahl von Monaten weitergeschoben wurde. Positive Zahlen schieben das Datum dabei in die Zukunft, wohingegen negative Werte zu einer Reise in die Vergangenheit fhren. Beispiel: add_months(sysdate, 12) = heute in einem Jahr. ermittelt fr das bergebene Datum den letzten Tag des darin enthaltenen Monats und gibt fr diesen Tag wieder ein Volldatum aus. Erhlt die Funktion beispielsweise als Wert den 03.10.2000, so liefert sie als Ergebnis den 31.10.2000 zurck. berechnet fr zwei Datumswerte die dazwischenliegende Anzahl von Monaten. Enthalten beide Daten die gleiche Tageszahl (z.B. 02.) oder beschreiben beide Datumswerte den jeweiligen Monatsletzten (z.B. 31.05 und 30.04), dann erhalten Sie als Ergebnis eine ganze Zahl. Ansonsten wird der in der Differenz enthaltene Monatsteil auf der Basis von 31 Tagen umgerechnet. Wann ist wieder Montag, diese Frage knnen Sie mit Hilfe der next_dayFunktion leicht beantworten. Hierzu bergeben Sie ihr als ersten Parameter ein Datum und danach als zweiten den gesuchten Wochentag in Form eines Textes. Als Ergebnis erhalten Sie das Datum fr diesen gesuchten Tag. Die Verwendung von next_day(sysdate, Mon) liefert Ihnen also das Datum des nchsten Montags. Als Krzel fr die gesuchten Wochentage knnen Sie entsprechend der Tage von Sonntag bis Samstag die Krzel Sun, Mon, Tue, Wed, Thu, Fri, Sat verwenden. Diese Funktion wird manchmal auch als Pseudospalte bezeichnet. Das ist insofern verstndlich, da sysdate ohne jeden Parameter verwendet wird und Funktionen ohne Parameter jedoch trotzdem blicherweise wenigstens mit einer leeren Klammer kodiert werden, was bei selbstdefinierten und parameterlosen Funktionen im brigen auch mglich ist, obwohl Sie auch diese ohne Klammern verwenden knnen. Aber mal abgesehen von diesen Formalien, so liefert Ihnen diese Funktion oder Pseudospalte in jedem Fall das aktuelle Tagesdatum auf Ihrem Datenbankserver, wobei der gelieferte Wert auch die aktuelle Tageszeit enthlt. Das ist eine beliebte Fehlerquelle, weshalb ich hierzu am Ende der Tabelle noch etwas ergnzen werde. Mit dieser Funktion knnen Sie ein Datum abschneiden. Hierzu mssen Sie neben dem Datum auch vorgeben, wo die Funktion die Schere ansetzen soll. Hierzu erhlt die Funktion einen zweiten Textparameter, mit dem diese Stelle des Datums markiert wird. Da diese Textkrzel auch noch an vielen anderen Stellen, beispielsweise bei der Datumskonvertierung, verwendet werden, mchte ich hier und jetzt lediglich auf die Tabelle 5.9 verweisen, in der Sie eine bersicht der wichtigsten Formatcodes finden. Auerdem finden Sie im Anschluss an diese Tabelle, also zwei Stze weiter, noch ein Anwendungsbeispiel zusammen mit der sysdate-Funktion.

last_day

months_ between

next_day

sysdate

trunc

Tabelle 5.7: Tabelle 5.7: bersicht wichtiger Datumsfunktionen

Kommen wir noch einmal zurck auf die Funktion sysdate, die wie gesagt, neben dem aktuellen Serverdatum auch dessen Zeit zurckliefert. Wenn Sie nun sysdate verwenden, um den Wert in einem Datumsfeld zu speichern oder damit zu verglei-

Einfhrung in PL/SQL

405

chen, dann sollten Sie schon einen Moment darber nachdenken, ob in dem Datumsfeld eine Zeitkomponente sinnvoll ist. Betrachten wir beispielsweise einmal das Datumsfeld gab in unseren Gehaltsdaten. Aufgrund unseres Datenimports enthalten alle unsere Gltigkeitsdaten lediglich ein Datum bzw. besitzen als Zeitanteil alle die Konstante 00:00:00. Ist es nun sinnvoll, wenn sich in einem solchen Datum irgendwann einmal ein konkreter Zeitanteil einschleicht, und wir hierdurch beispielsweise einen Gehaltsdatensatz erhalten, der am 01.12.2000 um 17:43:22 gltig wird. Ich denke, die Antwort auf diese Frage ist eindeutig nein und im anderen Fall mssen Sie sich allerdings auch damit abfinden, dass der Datensatz bei der folgenden Historienabfrage nicht selektiert wird:
where gab = (select max(gab) from gehalt b where b.persnr = a.persnr and b.lfdnr = a.lfdnr and b.gab <= '01.12.2000')

Das gespeicherte Datum ist nmlich nicht kleiner als der Vergleichswert 01.12.2000 00:00:00, sondern um ber 17 Stunden grer. Und auch bei der Verwendung von sysdate sieht wie purer Zufall aus, dass der Datensatz ab 17:44 pltzlich ausgewhlt wird. Im umgekehrten Fall, wo alle gespeicherten Daten den Zeitpunkt 00:00:00 enthalten, ist es natrlich egal, wenn wir die kleiner oder gleichRelation mit oder ohne Zeitanteil ausfhren. Wenn Sie also mit sysdate arbeiten und die von der Funktion gelieferten Ergebnisse dauerhaft speichern wollen, dann mssen Sie den darin enthaltenen Zeitwert eventuell loswerden, was Sie mit Hilfe der trunc-Funktion erledigen knnen.
SQLWKS> select to_char(sysdate, 'DD.MM.YYYY HH24:MI:SS'), 2> to_char(trunc(sysdate,'DD'), 'DD.MM.YYYY HH24:MI:SS') 3> from dual 4> TO_CHAR(SYSDATE,'DD TO_CHAR(TRUNC(SYSDA ------------------------------------29.09.2000 09:30:30 29.09.2000 00:00:00 1 row selected.

Wie schon gesagt, ist die trunc-Funktion in der Lage ein Datumswert abzuschneiden, wobei die bergebene Zeichenfolge DD dazu fhrt, dass die Funktion das Datum hinter dem Tag abschneidet, wobei man wissen muss, dass Oracle die Datumswerte in der Reihenfolge Jahr Monat Tag Stunden Minuten Sekunden speichert. Konvertierungsfunktionen Mit der nchsten Gruppe erhalten Sie einen berblick ber die wichtigsten Funktionen, mit denen Sie einen Wert explizit von einem Datentyp in einen anderen Typ umwandeln knnen.

406

PL/SQL-Programmierung

Funktion chartorowid

Beschreibung Wie schon bei der Behandlung der Pseudospalte rowid gesagt, handelt es sich hierbei um einen hexadezimalen Wert, normalerweise ohne Probleme in eine Zeichenfolge oder von dieser in den Typ rowid berfhrt werden kann. Dennoch empfehle ich Ihnen in solchen Fllen die Verwendung der Funktion chartorowid, die den bergebenen String in einen Datensatzzeiger vom Typ rowid umwandelt, denn in dem Fall ist Ihr Programm resistent gegen eventuellen nderungen der zugehrigen Regelwerke in zuknftigen Versionen. Hierbei handelt es sich um das Gegenstck zu chartorowid, d.h. diese Funktion wandelt den hexadezimalen Wert eines Datensatzzeigers in eine Zeichenfolge um. Mit dieser Funktion wandeln Sie ein bergebenes Datum bzw. eine bergebene Zahl in eine Zeichenfolge um. Hierzu mssen Sie als zweiten Parameter einen Formatcode spezifizieren, mit dem Sie die Regeln fr die Umwandlung festlegen. Eine bersicht der mglichen Formate finden Sie in der Tabelle 5.9. Als Gegenstck zur Funktion to_char wandelt to_date eine Zeichenfolge in einen Datumswert um. Auch hierbei gilt, dass Sie das zu verwendende Format als zweiten Parameter vorgeben mssen, wobei es sich auch diesmal um die gleichen Formatcodes der Tabelle 5.9 handelt. Diese Funktion wandelt eine Zeichenfolge in einen numerischen Wert um, wobei Sie auch diesmal wieder die Formatcodes der Tabelle 5.9 als Umwandlungshilfe verwenden knnen.

rowidtochar

to_char

to_date

to_number

Tabelle 5.8: Wichtige Funktionen zur Typkonvertierung

Zumindest in meinem Einsatzgebiet befinden sich die Konvertierfunktionen to_char, to_date und auch to_number, wenn auch nicht ganz so oft, im permanenten Einsatz. In der Regel sollten Sie alle diese Funktionen immer mit einem zweiten Parameter verwenden, mit dem Sie das bei der Konvertierung zu beachtende Format festlegen, denn ohne diesen zweiten Parameter knnen Sie die Funktionen auch ganz weglassen, da in dem Fall sowieso implizit konvertiert wird. Auf der anderen Seite muss man von der Vielzahl der verfgbaren Formatkrzel nicht unbedingt alle benutzen, so dass ich Ihnen in der Tabelle 5.9 einmal die wichtigsten Krzel vorgestellt habe. Auerdem vertragen diese drei Funktionen auch noch einen dritten Parameter, mit dessen Hilfe Sie sogenannte nls-Parameter (nls = national language support) also Anweisungen zur nationalen Sprachuntersttzung vorgeben knnen, was bei der Formatierung von Zahlen manchmal ganz hilfreich ist. Bei Datumswerten lautet die in unseren Breitengeraden sinnvolle nls-Anweisung
'NLS_DATE_LANGUAGE = German'

wohingegen man bei numerischen Werten wohl vor allem auf die korrekte Darstellung von Tausernder- und Dezimaltrennzeichen Wert legen drfte, was Sie durch Verwendung des folgenden nls-Parameters erreichen:
'NLS_NUMERIC_CHARACTERS = '',.'''

Einfhrung in PL/SQL

407

Formatcode DD MM YYYY HH24 MI SS DDD Day

Beschreibung Platzhalter fr den Tag im Datum in zweistelliger Form also eventuell mit fhrender Null. Entsprechend DD dient dieser Code als Platzhalter fr den Monat im Wertebereich von 01 bis 12. Mittlerweile sollte es wohl blich sein, vierstellige Jahreszahlen zu verwenden, weshalb der Y-Formatcode entsprechend hufig verwendet wird. Code fr die Darstellung der Stunden im 24-Stunden-Format. Platzhalter fr die Minuten im Wertebereich von 00 bis 59. Platzhalter fr die Sekunden ebenfalls im Wertebereich von 00 bis 59. liefert bzw. steht fr den Tag in Relation zum 01.01 des Jahres. Dieser Code reprsentiert den im Datum enthaltenen Tag in Klarschrift. So liefert day fr den 29.09.2000 den Wert friday, Day dahingegen Friday und DAY letztendlich FRIDAY. entspricht im Prinzip der Kodierung Day, wobei diesmal Kurztexte (ersten drei Buchstaben) geliefert bzw. erwartet werden. hnlich wie bei dem vorhergehenden Formatcode unterscheidet Oracle auch diesmal zwischen Ground Kleinschreibweise. liefert hnlich wie Day den im Datum enthaltenen Monat im Klartext. Genau wie bei der Tagesbezeichnung gilt auch hier wieder das Gesagte in Bezug auf die Gro- und Kleinschreibweise. Dieser Code entspricht praktisch der Verwendung von Dy auf Monatsbasis, d.h. hierdurch erhalten Sie ein dreistelliges Monatskrzel. Entsprechend der gro- bzw. kleingeschriebenen Anwendung erhalten Sie als Ergebnis klein, gro oder gemischt geschriebene Krzel (jan, feb, mar, ..., dec). Platzhalter fr eine Ziffer. Ebenfalls Platzhalter fr eine Ziffer, wobei hierbei allerdings fhrende Nullen unterdrckt werden. Platzhalter fr den Dezimalpunkt. Platzhalter fr das Dezimaltrennzeichen entsprechend der nls-Einstellungen. Platzhalter fr das Vorzeichen. Platzhalter fr ein Tausendertrennzeichen entsprechend der nls-Einstellung.

Dy

Month

Mon

0 9 . D MI G

Tabelle 5.9: bersicht wichtiger Formatcodes

Neben diesen Formatcodes knnen Sie innerhalb des zu verwendenden Formatstrings weitere beliebige Sonder- und Trennzeichen verwenden. Das ist zumindest so lange kein Problem, wie das von ihnen verwendete Zeichen nicht als Formatcode interpretiert wird. In dem Fall mssen Sie die verwendeten Zeichen in doppelten Anfhrungszeichen setzen, d.h. sofern Sie die Buchstabenfolge dd nicht als Formatcode interpretiert wissen mchten, dann mssen Sie sie folgendermaen verwenden:
to_char(sysdate, '"dd"dd.mm.yyyy')

408

PL/SQL-Programmierung

Ich finde, mit diesen Formatcodes muss man einfach einmal spielen, was bei den Datumswerten unter zu Hilfenahme von sysdate auch prima mglich ist. Ein paar Anregungen zum Experimentieren mit der Formatierung von Datumswerten finden Sie im Listing 5.6 und ein Analoges Beispiel fr numerische Werte steht Ihnen mit dem Beispiel 5.7 zur Verfgung.
select to_char(sysdate, 'DD.MM.YYYY') Datum from dual; select to_char(sysdate, 'DD.MM.YYYY HH24:MM:SS') Datum from dual; select to_char(sysdate, '"DD"DD.MM.YYYY') Datum from dual; select to_char(sysdate, '"... heute ist "Day" der "dd." "Month" also der "ddd."Tag im Jahr "yyyy', 'NLS_DATE_LANGUAGE = German') Datum from dual; DATUM ---------29.09.2000 29.09.2000 10:09:00 DD29.09.2000 ... heute ist Freitag der 29. September also der 273.Tag im Jahr 2000
Listing 5.6: Beispiele fr den Gebrauch der Formatcodes fr Datumswerte

select to_char(-232323.22, '9999G990D99MI', 'NLS_NUMERIC_CHARACTERS = '',.''' ) from dual; select to_char(0.22, '9999G990D99MI', 'NLS_NUMERIC_CHARACTERS = '',.''' ) from dual; select to_char(0.22, '9999G990D99MI') from dual; select to_char(2345, '000000MI') from dual; select to_char(2345, '000000') from dual; TO_CHAR(.....

-----------232.323,220,22 0.22 002345 002345


Listing 5.7: Beispiele fr die Formatierung von Zahlen

Gerade die letzten beiden Beispiele liefern noch einmal einen interessanten Randaspekt, wenn es beispielsweise darum geht, Ganzzahlen in entsprechende Zeichenfolgen umzuwandeln. Ohne weitere Formatierung erhalten Sie als erstes Zeichen immer einen Platzhalter fr das Vorzeichen. Somit mssen Sie dieses entweder mit Hilfe des mi-Formatcodes ans Ende der Zahl verlagern oder die umgewandelte Zahl in einem zweiten Schritt mit Hilfe der ltrim-Funktion trimmen.

Einfhrung in PL/SQL

409

Sonstige Funktionen Damit wren bei der derjenigen Funktionsgruppe angekommen, die bei dem Versuch irgendetwas nach Kategorien zu ordnen meistens entsteht und alles aufnimmt, was in den anderen Gruppen nicht so richtig reinpasst.
Funktion decode Beschreibung ermglicht die Vertextung bzw. Umsetzung eines Feldes mit Hilfe der in der Funktion verwendeten Schlssel/Werteliste: decode(<Feldname>, wert1, text1, wert2, text2...) greatest liefert den grten der bergebenen Argumente zurck. Das erste Argument regelt dabei die Show, d.h. es legt fest in welches Datenformat alle anderen Argumente bei Bedarf konvertiert werden und welche Regeln bei der Ermittlung des grten Wertes gelten. Hierbei handelt es sich quasi um das Gegenstck von greatest, d.h. mit Hilfe dieser Funktion erhalten Sie den kleinsten der bergebenen Argumente. Ansonsten gilt das zu greatest Gesagte auch hier ganz analog. Mit Hilfe dieser Funktion knnen Sie den Wert null substituieren. Die Funktion bentigt hierzu zwei Parameter. Mit Hilfe des ersten bergeben Sie die zu berprfende Spalte und als zweiten spezifizieren Sie den zu verwendenden Ersatzwert, sofern der erste Parameter den Wert null enthlt. Am Ende der Tabelle finden Sie noch ein paar Hinweise zur Verwendung der nvl-Funktion. Diese Funktion liefert eine Ganzzahl, die den aktuellen Benutzer eindeutig identifiziert. Mit Hilfe dieses Wertes knnen Sie in vielen anderen Tabellen bzw. Views (z.B. dba_users.user_id oder v$session.user#) einsteigen. hnlich zu uid liefert die user-Funktion die Kennung des aktuellen Benutzers. Mit Hilfe dieser Funktion knnen Sie fr den aktuellen Benutzer verschieden Einstellungen der Datenbanksitzung abfragen. Hierzu erhlt die Funktion einen Textparameter, der die gewnschte Information spezifiziert. Bei diesen Codes ist aus meiner Sicht allerdings nur der Schlssel SESSIONID erwhnenswert, mit dem Sie in anderen Tabellen bzw. Views (z.B. v$session.audsid) Abfragen durchfhren knnen.

least

nvl

uid

user userenv

Tabelle 5.10: Tabelle 5.10: bersicht weiterer wichtiger Funktionen

Nun noch ein paar Worte zur nvl-Funktion. Deren Verwendung erspart einem oftmals die Konstruktion aufwendiger Berechnungen oder Abfragen. Sollen wir zum Beispiel alle aktiven Mitarbeiter selektieren, dann sind das diejenigen, deren Austritt entweder leer oder grer dem aktuellen Tagesdatum sind, was Sie folgendermaen abfragen knnten:
select persnr, lfdnr from bvs where austrt is null or austrt > sysdate;

410

PL/SQL-Programmierung

Hierdurch schleicht sich allerdings eine or-Verknpfung in unsere Auswahlabfrage ein, was bei umfangreicheren Selektionskriterien entsprechend zu bercksichtigen ist. Die Verwendung der nvl-Funktion bietet einen eleganteren Lsungsansatz und fhrt zu folgender where-Klausel:
where nvl(austrt, sysdate+1) > sysdate

In dem Fall werden nicht gefllte Austritte einfach durch einen Wert ersetzt, der bei der anschlieenden Selektion in der gewnschten Weise bercksichtigt wird.

5.1.5

Ausgabe von Meldungen

Mit Hilfe spezieller Funktionen sind Sie in der Lage, whrend der Ausfhrung Ihres PL/SQL-Programms spezielle Meldungen auszugeben, um beispielsweise auf besondere Situationen oder Fehler hinzuweisen. Dabei gibt es zur Ausgabe von Fehlernachrichten spezielle Kommandos, die neben der Meldung auch automatisch dafr sorgen, dass das aktuell laufende Programm abgebrochen wird, wohingegen die ausgegebenen Hinweise gesammelt und erst nach Beendigung des Programms bereitgestellt werden. Oft werden die Hinweismeldungen auch dazu benutzt, um eine gewisse Ablaufverfolgung des Programms durchzufhren. Zwar existieren hierzu auch spezielle Tools, die eventuell im Zusammenspiel mit der Client-Engine mehr Mglichkeiten bieten, jedoch sind solche Tools zum einen nicht immer verfgbar und zum anderen kennt man sich mit deren Umgang vielleicht auch nicht gut genug aus. Hinweise ausgeben Zur Aufbereitung und Ausgabe von Hinweisen bietet Oracle verschiedene Funktionen an, die Ihnen durch das Paket dbms_output bereitgestellt werden. Mit Hilfe dieses Pakets wird ein interner Puffer verwaltet, der am Ende Ihres Programms oder Skripts am Bildschirm ausgegeben werden kann. Das passiert allerdings nur, wenn Sie den Parameter serveroutput auf on gestellt haben, was Sie mit Hilfe der folgenden set-Anweisung durchfhren knnen:
set serveroutput on;

Diese Einstellung gilt fr die aktive Datenbanksitzung oder solange, bis Sie diese Einstellung wieder auf den Ausgangswert off setzen. Die fr die Erstellung von Meldungen wesentlichste Prozedur im dbms_output-Paket heit put_line und kopiert die als Parameter bergebene Zeichenkette in diesen eben beschriebenen internen Puffer.
begin dbms_output.put_line('Hallo, hier bin ich'); end;

Dabei fgt diese Prozedur genauer gesagt eine komplette Zeile in diesen Puffer, d.h. man kann sich diesen internen Puffer wie ein mehrzeiliges Textfeld vorstellen, das mit Hilfe der put_line-Funktion vollgeschrieben wird und wobei jede dieser Zeile

Einfhrung in PL/SQL

411

maximal 255 Zeichen lang ist. Dieses Textfeld bzw. der gesamte Puffer ist im brigen standardmig 2000 Byte gro und kann bei Bedarf mit Hilfe der Paket-Prozedur dbms_output.enable vergrert werden.
begin dbms_output.enable(20000); end;

Auerdem wird die Pufferung der erzeugten Hinweise hierdurch erneut eingeschaltet, sofern Sie dieses Verfahren zuvor durch Anwenden der dbms_output.disable-Prozedur abgeschaltet haben. Ein solches Abschalten hat allerdings auch zur Konsequenz, dass die bisher gepufferten Daten dabei verloren gehen, da der interne Puffer hierbei gelscht wird. Soll keine ganze Zeile, sondern nur ein einzelner Text bzw. ein einzelnes Feld in den Ausgabepuffer kopiert werden, dann knnen Sie hierzu die put-Prozedur des Pakets verwenden und einen Zeilenwechsel vielleicht irgendwann durch das Aufrufen der new_line-Prozedur veranlassen. Das folgende Beispiel entspricht also der soeben durchgefhrten Textausgabe, wobei die Ausgabe diesmal in zwei Schritten erfolgt und durch einen manuellen Zeilenwechsel abgeschlossen wird.
Begin dbms_output.put('Hallo, '); dbms_output.put('hier bin ich'); dbms_output.new_line; end;

Das ist auch schon fast alles, was in dem dbms_output-Paket enthalten ist. Der Vollstndigkeit halber mchte ich noch erwhnen, dass Sie in dem Paket neben den eben beschriebenen Prozeduren noch die beiden Objekte get_line und get_lines finden, mit denen Sie die in den Puffer geschriebenen Daten wieder auslesen knnen. Die Verwendung dieser beiden Prozeduren ist brigens im Kopf des Pakets beschrieben, d.h. sofern Sie die beiden wirklich einmal verwenden mssen, dann finden Sie dort weiterhelfende Informationen. Ansonsten finden Sie eine Beschreibung des gesamten Pakets auch im Kapitel 12 des Buchs Oracle8 Application Developer's Guide bzw. schlagen Sie im dortigen Index einfach dbms_output nach, um die entsprechenden Textstellen zu finden. Meistens wird das dbms_output-Paket dazu verwendet, den Ablauf eines PL/SQLProgramms zu kontrollieren oder whrend der Ausfhrung den Wert bestimmter Variablen zu protokollieren. Dabei kann das Paket in allen PL/SQL-Objekten, also auch in Triggern, angewendet werden. Wenn Sie hierbei anschlieend eine Transaktion auf die Tabelle ausfhren, fr die ein Trigger mit Hinweismeldungen angelegt wurde, dann erhalten Sie die erstellten Hinweise nach der Durchfhrung der Transaktion auf dem Bildschirm. Fehlermeldungen generieren Wenn Sie whrend der Programmausfhrung eine Fehlermeldung und einen damit verbundenen Programmabbruch erzeugen mchten, dann knnen Sie dies mit

412

PL/SQL-Programmierung

Hilfe der Prozedur raise_application_error erreichen. Diese Prozedur ist brigens Bestandteil des Pakets dbms_standard, weshalb sie ohne Nennung des Paketnamens verwendet werden kann. Die Prozedur erhlt blicherweise zwei bis drei Parameter. Mit Hilfe des ersten Parameters mssen Sie eine Fehlernummer vorgeben, wobei hierfr der Nummernkreis von 20000 bis 20999 fr anwendungsspezifische Fehler reserviert wurde. Der zweite Parameter enthlt die bis zu 2048 Zeichen lange Fehlermeldung. Der dritte Parameter wird standardmig mit dem Wert false (falsch) vorbelegt und fhrt dazu, dass nur die von Ihnen ausgegebene Fehlernachricht ausgegeben wird. Verwenden Sie stattdessen den Wert true (wahr), dann werden auch eventuell vorhergehende Fehler angezeigt, was bei der Programmierung einer Fehlerbehandlungsroutine interessant sein kann. In diesem Workshop finden Sie bei der Beschreibung solcher Fehlerbehandlungsroutinen auch noch weitergehende Informationen zu raise_application_error. Das nun folgende kleine Beispiel (vgl. Listing 5.8) zeigt Ihnen die Anwendung der raise_application_error-Routine mitsamt den Ausgaben, die hierbei am Bildschirm des SQL-Editors erscheinen. Mit Hilfe des dbms_out-Pakets dokumentieren wir dabei, dass unser Programm nach Ausgabe der Meldung wirklich abbricht, denn die kurz vor Programmende erzeugte Hinweismeldung wird nicht ausgegeben.
Begin dbms_output.put_line('Anfang'); raise_application_error(-20000,'Keine Lust zum Arbeiten'); dbms_output.put_line('Ende'); end; ORA-20000: Keine Lust zum Arbeiten ORA-06512: at line 3 Anfang
Listing 5.8: Verwenden von raise_application_error

5.1.6

Konditionalbedingungen

Nur selten luft ein Programm geradlinig von oben nach unten bzw. von seinem Anfang bis zu seinem Ende durch. In der Regel sind bestimmte Programmbefehle an besondere Bedingungen gebunden, so dass zur Laufzeit entschieden wird, ob spezielle Befehle oder vielleicht sogar Unterprogramme aufgerufen werden oder nicht. Die Programmierung solcher Bedingungen erfolgt in PL/SQL genau wie in den meisten anderen Programmiersprachen mit Hilfe der if-Anweisung, dabei entspricht die einfache Form dieser Anweisung dem folgenden Schema:
if <Bedingung> then <PL/SQL-Anweisungen> [else <Alternative PL/SQL-Anweisungen>] end if;

Einfhrung in PL/SQL

413

Ist die hinter dem if-Befehl spezifizierte Bedingung erfllt, so werden die hinter dem Schlsselwort then kodierten Anweisungen ausgefhrt und anschlieend wird die Programmausfhrung mit den Anweisungen fortgesetzt, die der end if-Anweisung folgen. Ist die Bedingung nicht erfllt, dann verzweigt das Programm zu den Anweisungen, die der else-Klausel folgen, sofern solche Anweisungen berhaupt vorhanden sind, denn die Kodierung eines else-Zweigs ist optional. Wie Sie dem Schema allerdings richtig entnehmen knnen, ist die Vorgabe der then-Anweisungen im Unterschied zu einigen anderen Programmiersprachen allerdings nicht wahlfrei. Das erkennt man im brigen schon daran, dass hinter dem then genau wie hinter dem else kein Semikolon steht, d.h. sowohl if als auch else alleine bilden keine vollstndige Anweisung, denn diese werden ja bekanntlich mit einem Semikolon beendet. Ansonsten gibt es allerdings kaum besondere Restriktionen. Die if-Anweisungen knnen im Programm beispielsweise beliebig geschachtelt werden. Das geht prinzipiell so lange, bis Sie die bersicht verlieren, d.h. hier bilden wir und nicht das System die Grenzen des Mglichen. Formal mssen Sie dabei nur beachten, dass jedem if irgendwann einmal das zugehrige end if folgen muss. Was die mit der if-Anweisung verbundene Ausfhrungsbedingung angeht, so gilt hier im Prinzip das Gleiche, was Sie schon bei den Abfragen bei der Beschreibung der where-Klausel gelesen haben bzw. dort nachlesen knnen. So eine Bedingung besteht also wieder aus einem oder mehreren Ausdrcken, die jeweils mit Hilfe der verfgbaren Vergleichsoperatoren (vgl. Kapitel 3.1.2) verglichen und wo mehrere solcher Vergleichsbedingungen mit Hilfe der vorhandenen Verknpfungsoperatoren (vgl. Tabelle 3.1) verbunden werden.
if a > b then; dbms_output.put_line('then-Zweig'); else dbms_output.put_line('else-Zweig'); if b > c then dbms_output.put_line('then-2-Zweig'); end if; end if;

Oft hat man beim Programmdesign das Problem, dass der else-Teil einer if-Bedingung nicht unbedingt immer ausgefhrt werden soll, sondern selbst wiederum von einer weiteren, also geschachtelten Unterbedingung abhngig ist. Fr solche Flle hat sich in den letzten Jahren in vielen Programmiersprachen eine besondere Unterform der if-Abfrage entwickelt, die dem folgenden Schema entspricht:
if <Bedingung-1> then <PL/SQL-Anweisungen> elsif <Bedingung-2> then <PL/SQL-Anweisungen> elsif <Bedingung-3> then <PL/SQL-Anweisungen> [else

414

PL/SQL-Programmierung

<Alternative PL/SQL-Anweisungen>] end if;

Ist die erste if-Bedingung nicht erfllt, dann wird die nchstfolgende elsif-Bedingung untersucht, der ggf. die dritte und vierte usw. Bedingung folgt. Wenn keine der vorhandenen Bedingungen erflltl ist und damit zur Ausfhrung der zugehrigen Anweisungen fhrt, dann kommen die im else-Zweig kodierten Programmschritte zur ausfhren, was natrlich nur geht, wenn eine solcher Zweig berhaupt vorhanden ist. Sprungmarken Zusammen mit den if-Anweisungen kommen zumindest mir immer noch sofort die Sprungmarken in den Sinn, was nicht daran liegt, dass ich sie so oft verwende, sondern frher, so vor ungefhr 60 Jahren, da bildeten if-Befehl und Sprungbefehl irgendwie eine Einheit, was heutzutage wegen der vielen anderen und mchtigen Konstruktionsmglichkeiten sicherlich nicht mehr gilt. Dennoch gibt es den Befehl immer noch in nahezu allen Programmiersprachen und diejenigen Sprachen, die von sich behaupten, dass sie frei von Sprngen wren, haben das nur dadurch erreicht, indem sie spezielle Sprungbefehle einfach verschleiern, denn ein exit ist im Prinzip auch nichts anderes als der Sprung zu einer vordefinierten Marke hinter der zugehrigen Schleife. Doch lassen wir diesen Glaubenskrieg links liegen und wenden uns wieder dem eigentlichen Thema zu. In Ihren PL/SQL-Programmen haben Sie die Mglichkeit, Sprungmarken zu setzen. Eine solche Sprungmarke besteht im Prinzip aus einem beliebigen Wort, einer Art berschrift, mit der die zugehrige Programmstelle gekennzeichnet wird. Eine solche Sprungmarke wird in PL/SQL von doppelten Kleiner- und Grerzeichen eingeschlossen und besteht ansonsten im Regelfall nur aus Buchstaben und Ziffern.
<<Sprungmarke>>

Wenn Sie auerdem noch andere besondere Zeichen (Minus, Leerzeichen usw.) innerhalb einer Sprungmarke verwenden wollen, dann mssen Sie diese insgesamt mit doppelten Anfhrungszeichen einschlieen.
<<"Sprungmarke 2-23">>

Eine solche Sprungmarke knnen Sie in Ihrem Programm mit Hilfe der goto-Anweisung ansteuern, indem Sie den Befehl zusammen mit der gewnschten Sprungmarke verwenden. Hierbei mssen Sie allerdings folgende Einschrnkungen beachten: 1. Sie drfen nicht in eine if-then-else-Anweisung hineinspringen, was im brigen auch fr Sprnge zwischen den einzelnen Zweigen gilt, denn die sind ebenfalls verboten. 2. Sie drfen nicht in tieferliegende Programmblcke springen. 3. Sie drfen eine Prozedur oder Funktion nicht per goto-Anweisung verlassen. 4. Sie drfen aus einer Fehlerbehandlungsroutine nicht in den zugehrigen Block zurckspringen.

Einfhrung in PL/SQL

415

Ich wei nicht, wie es Ihnen geht, aber ich empfinde keine der vier genannten Einschrnkungen in irgendeiner Weise restriktiv. Wie schon gesagt, bentigt man den Befehl in der heutigen Zeit aufgrund der vielen anderen Mglichkeiten sowieso nur noch sehr sehr selten. Trotzdem habe ich Ihnen im Beispiel 5.9 eines meiner Lieblingsbeispiele serviert, indem Sie die sinnvolle Anwendung des gotoBefehls demonstriert bekommen.
begin goto anfang; <<"schritt-4">> dbms_output.put_line('Schritt-4'); goto ende; <<"schritt-3">> dbms_output.put_line('Schritt-3'); goto "schritt-4"; <<"schritt-2">> dbms_output.put_line('Schritt-2'); goto "schritt-3"; <<anfang>> dbms_output.put_line('Anfang'); goto "schritt-2"; <<ende>> dbms_output.put_line('Ende'); end; Statement processed. Anfang Schritt-2 Schritt-3 Schritt-4 Ende
Listing 5.9: Anwendung des goto-Befehls

5.1.7

Schleifen

Wie schon bei der Einleitung zu den Konditionalbedingungen gesagt, luft ein Programm nur selten sequentiell vom Start zum Programmende, sondern manche Programmteile werden nur unter bestimmten Bedingungen ausgefhrt, wohingegen andere Teile hufiger wiederholt werden mssen. Solche Wiederholungen bzw. Schleifen knnen auch in PL/SQL mit Hilfe entsprechender Anweisungen programmiert werden.

416

PL/SQL-Programmierung

Je nach verwendeter Programmiersprache gibt es immer verschiedene Varianten, um diese Schleifen zu programmieren. Unter PL/SQL stehen Ihnen die im Folgenden beschriebenen Schleifen-Konstruktionen zur Verfgung, wobei Sie ein kleines Anwendungsbeispiel ganz am Ende des Kapitels im Listing 5.10 finden:

while loop-Schleife Bei der while loop-Schleife werden die in der Schleife programmierten Anweisung so lange ausgefhrt, wie die hinter der while-Anweisung kodierte Bedingung erfllt ist. Ist diese Bedingung schon beim Erreichen der Schleife nicht mehr erfllt, dann wird die Schleife folglich gar nicht durchlaufen. Die Programmierung einer while loop-Schleife entspricht dem folgenden Schema:
while <Bedingung> loop <Anweisungen> end loop;

loop-Schleife Bei der loop-Schleife handelt es sich um eine Sonderform der soeben beschriebenen while loop-Schleife. Wie Sie schon an der Begriffsfhrung erkennen knnen, fehlt hierbei die while-Klausel und damit die Abbruchbedingung der Schleife, d.h. loop-Schleifen laufen zunchst einmal endlos lange. Damit das in der Praxis dann doch nicht passiert, denn Endlosschleifen gelten nach neusten wissenschaftlichen Erkenntnissen als Fehler, gibt es die exit-Anweisung, mit der Sie die Schleife verlassen knnen, so dass die Verwendung der loop-Schleife nach etwa folgendem Schema erfolgt:
loop <Anweisungen> if <Bedingung> then exit; end if; end loop;

for loop-Schleife Bei der for loop-Schleife, die manchmal auch einfach Zhlschleife genannt wird, legen Sie von vornherein explizit fest, wie oft die Schleife durchlaufen wird, indem eine Laufvariable entsprechend eines vorgegebenen Intervalls variiert wird, bis die hintere Intervallgrenze erreicht wird. Die Verwendung einer for loopSchleife sieht in etwa folgendermaen aus:
for <Laufvariable> in [reverse] <Interval> loop <Anweisungen> end loop;

Normalerweise wird das vorgegebene Intervall in aufsteigender Reihenfolge durchlaufen, d.h. die Laufvariable nimmt mit jedem Schleifendurchlauf den nchsten Wert des Intervalls an.

Einfhrung in PL/SQL

417

exit-Anweisung Zum vorzeitigen Verlassen einer Schleife existiert in PL/SQL die exit-Anweisung. Es drfte nur wenig Anforderungen geben die dazu fhren, dass der exit-Befehl direkt verwendet wird, d.h. in aller Regel wird er innerhalb einer if-Anweisung verwendet, mit der die besondere Ausstiegsbedingung fr die Schleife festgelegt wird. Aus diesem Grund gibt es fr die exit-Anweisung auch eine weitere Variante, in der Sie die Abbruchbedingung mit Hilfe des Schlsselwortes when direkt zusammen mit dem exit-Befehl Programmieren knnen.
exit when <Abbruchbedingung>

Schleifen benennen In bestimmten Ausnahmesituationen kann es sinnvoll sein, den einzelnen Schleifen eine Markierung in Form einer gewhnlichen Sprungmarke zu geben, die direkt vor dem Anfang der Schleife gesetzt werden muss. Optional knnen Sie den verwendeten Sprungnamen auch noch einmal an das Ende der Schleife direkt hinter der end loop-Anweisung stellen:
<<Schleife1>> loop ... end loop Schleife1;

Aus meiner Sicht sind solche Benennungen nur in bestimmten Ausnahmesituationen sinnvoll, denn hierdurch haben Sie bei geschachtelten Schleifen die Mglichkeit, mit Hilfe einer weiteren exit-Variante gezielt aus mehreren Schleifen herauszuspringen. Das folgende Beispiel demonstriert diese Mglichkeit, indem mit Hilfe der exit-Anweisung als allen Schleifen herausgesprungen wird:
<<Schleife1>> loop loop exit schleife1 when end loop; end loop;

Anwendungsbeispiel
declare i integer := 0; j integer := 0; k integer := 0; begin dbms_output.enable(50000); loop i:=i+1;

418

PL/SQL-Programmierung

j:= 1; while j < 10 loop for k in reverse 1..10 loop dbms_output.put('Schleife=> '); dbms_output.put(to_char(i, '99.')); dbms_output.put(to_char(j, '99.')); dbms_output.put(to_char(k, '99')); dbms_output.new_line; end loop; j:=j+1; end loop; exit when i=10; end loop; end;
Listing 5.10: Anwendungsbeispiel zur Schleifenverwendung

5.1.8

Datenbankabfragen

Innerhalb eines PL/SQL-Programms knnen Sie zu jedem beliebigen Zeitpunkt irgendwelche Datenbankaktionen ausfhren. Dabei knnen Sie beispielsweise innerhalb der where-Bedingung auf alle verfgbaren Variablen Bezug nehmen, so dass auf diese Weise dynamische SQL-Kommandos entstehen:
update personalien set name = xname where persnr = xpnr;

In diesem Beispiel wird der Name fr einen speziellen Mitarbeiter gendert, wobei der neue Name bzw. die zu ndernde Personalnummer erst zur Laufzeit durch die Werte in den Variablen xname bzw. xpnr feststehen. Wesentlich interessanter als die Beschreibung solcher parametrisierten nderungsabfragen ist jedoch die Fragestellung, wie innerhalb eines PL/SQL-Programms irgendwelche Tabellen der Datenbank gelesen werden knnen. Die einfachste Variante, bestimmte Felder aus der Datenbank in einem PL/SQL-Programm zu lesen besteht darin, eine gewhnliche Auswahlabfrage zu kodieren, und die selektierten Felder mit Hilfe der into-Klausel in entsprechende Variablen oder eine geeignete Struktur zu kopieren.
declare xpersnr personalien.persnr%type; xname personalien.name%type; begin select persnr, name into xpersnr, xname

Einfhrung in PL/SQL

419

from personalien where persnr = '7000188'; dbms_output.put_line(xname); end;

Allerdings fhrt diese Abfragetechnik zu einem Laufzeitfehler, wenn die eingesetzte Abfrage nicht genau einen Datensatz zurckliefert. Positiv ausgedrckt gibt es also Probleme, wenn Ihre Abfrage keinen oder mehrere Datenstze liefert. Fr dieses Problem gibt es genau genommen drei verschiedene Lsungsanstze: 1. Sie verwenden anstelle einer solchen Abfrage einen Cursor. Das ist natrlich wesentlich aufwndiger, denn wie Sie schon gesehen haben bzw. gleich noch einmal sehen werden, mssen Sie den Cursor nicht nur definieren, sondern auch mit Hilfe spezieller Befehle verarbeiten. Dafr ist die ganze Anwendung dann allerdings fehlertolerant, denn sofern der Cursor keinen Datensatz liefert erkennen Sie das mit Hilfe der entsprechenden Statusanzeige %notfound und ansonsten wird der Cursor nach dem Lesen des ersten Satzes wieder geschlossen, so dass auch die Anlieferung mehrerer Datenstze kein Problem mehr darstellt. 2. Die zweite Mglichkeit besteht darin, die Abfrage in einem speziellen Block zu kapseln und den Block mit einer geeigneten Fehlerbehandlungsroutine auszustatten. Natrlich fhrt auch das zu einem gewissen Mehraufwand in Form entsprechender Programmlogik, so dass auch diese Lsung eigentlich nicht so recht berzeugen kann. 3. Die einfachste Variante zur Lsung des Problems besteht in der Anwendung eines kleinen Tricks. Wie Sie sich vielleicht erinnern, hatte die Verwendung von Aggregatfunktionen in einer Abfrage die Nebenwirkung, dass die Abfrage hierdurch immer Ergebnisse zurckliefert. Wenn wir die bentigten Spalten also mit Hilfe der max-Funktion abfragen, dann ist sichergestellt, dass wir immer genau einen Wert erhalten und wenn die Abfrage gar keinen Datensatz selektiert, dann erhalten wir aufgrund der max-Funktion immerhin noch den Wert null. Die dritte Variante, scheint auf den ersten Blick die einfachste Lsung zu bieten, was sich besttigt, wenn man sich das genderte Programm einmal anschaut:
declare xpersnr personalien.persnr%type; xname personalien.name%type; begin select max(persnr), max(name) into xpersnr, xname from personalien where persnr = '7000188'; dbms_output.put_line(xname); end;

420

PL/SQL-Programmierung

Verwenden von Cursorn Sofern Sie in Ihrem Programm nicht nur einen einzelnen Datensatz bentigen, sondern die aus einer Abfrage resultierenden Datenmenge verarbeiten mssen, dann ist es notwendig hierfr einen entsprechenden Cursor zu definieren. In diesem Workshop (vgl. Kapitel 3.3.5) haben Sie schon den Cursor als Instrument zum Durcharbeiten einer Datenmenge kennen gelernt. Im Prinzip handelt es sich bei einem solchen Cursor um ein Objekt, das es Ihnen ermglicht in einem Programm eine spezielle Abfrage auszufhren und die zugehrigen Datensatz im Rahmen einer Schleife einzeln zu empfangen bzw. zu verarbeiten. Hierzu mssen Sie den Cursor im Deklarationsteil des Programms bzw. des zugehrigen Blocks zunchst einmal definieren. Hierbei wird neben dem Namen des Cursors auch die damit verbundene Abfrage festgelegt. Das folgende Beispiel erzeugt den Cursor read_pers, mit dem zwei Felder der Tabelle personalien gelesen werden.
declare cursor read_pers is select persnr, name from personalien order by name;

Innerhalb des Programms knnen Sie den Cursor bei Bedarf ffnen, so dass die damit verbundene Abfrage ausgefhrt wird. Anschlieend haben Sie die Mglichkeit, die einzelnen Datenstze der Reihe nach abzufordern. Wird der Cursor nicht mehr bentigt, bzw. wurden alle Datenstze gelesen, dann sollte er innerhalb des Programms wieder geschlossen werden, was auch zu einer Freigabe der an den Cursor gebundenen Ressourcen fhrt. Dabei erfolgt das ffnen eines Cursors erfolgt mit Hilfe der open-Anweisung. Fr das Abrufen der einzelnen Datenstze existiert die Anweisung fetch und geschlossen wird der Cursor mit Hilfe eines close-Befehls. In dem folgenden Beispiel 5.11 finden Sie ein kleines Beispiel fr die Verwendung eines Cursors, indem die Personalien der Reihe nach gelesen und die jeweiligen Namen ausgegeben werden.
declare cursor read_pers is select persnr, name from personalien; xpersnr personalien.persnr%type; xname personalien.name%type not null := ' '; begin open read_pers; loop fetch read_pers into xpersnr, xname; exit when read_pers%notfound; dbms_output.put_line(xname); end loop; end;
Listing 5.11: Datenstze mit Hilfe eines Cursors verarbeiten

Einfhrung in PL/SQL

421

Wie Sie an dem Beispiel 5.11 sehen knnen, erfolgt die Verarbeitung der selektierten Datenstze mit Hilfe einer loop-Schleife. Damit diese Endlosschleife nicht bis zum jngsten Tag luft, programmieren wir mit Hilfe der exit-Anweisung eine geeignete Abbruchbedingung, indem wir die Statusvariable notfound des Cursors abfragen. Diese enthlt nmlich genau dann den Wert true, wenn der vorherige fetch-Befehl wegen des erreichten Cursorendes keinen Datensatz mehr geliefert hat. Insgesamt stehen Ihnen bei einem Cursor die in der Tabelle 5.11 gezeigten Statusvariablen zur Verfgung.
Statusvariable %found %isopen %notfound %rowcount Beschreibung ist true, wenn der vorherige fetch einen Datensatz geliefert hat. enthlt den Wert true, wenn der Cursor geffnet wurde. entspricht not %found und ist damit nur dann wahr, wenn der vorherige fetch-Versuch nicht erfolgreich war. zhlt alle gelesenen Datenstze, d.h. der Wert dieser Statusvariablen erhht sich mit jedem fetch-Befehl.

Tabelle 5.11: Beschreibung der Statusvariablen eines Cursors

for-Schleifen fr Cursor Zum Abarbeiten der vom Cursor gelieferten Datenstze existiert im PL/SQL-Sprachumfang eine spezielle Variante der for-Schleife, mit der Sie die gelieferten Datensatz vollstndig durchlaufen knnen. Dabei fhrt diese spezielle Schleife auch implizit die open- und close-Befehle fr den Cursor aus, so dass sich unser letzten Beispiel noch einmal deutlich verkrzen lsst (vgl. Listing 5.12).
declare cursor read_pers is select persnr, name from personalien; begin for xrec in read_pers loop dbms_output.put_line(xrec.name); end loop; end;
Listing 5.12: Anwenden eines Cursors zusammen mit der speziellen for-Schleife

Wenn Sie dieses Beispiel mit der vorhergehenden Definition der for loop-Schleife vergleichen, dann werden Sie vor allem folgende Unterschiede erkennen:

Anstelle des vorgegebenen Schleifenintervalls tritt jetzt einfach der Name des Cursors, d.h. das Intervall heit ganz einfach vom ersten bis zum letzten Datensatz. Die Laufvariable der Schleife, die ich in unserem Beispiel xrec genannt habe, wird vom Programm automatisch angelegt. Hierbei handelt es sich um eine Struktur, die Sie auch manuell folgendermaen definieren knnten:

422

PL/SQL-Programmierung

xrec read_pers%rowtype;

Um das noch einmal deutlich zu sagen: Die for-Schleife verwendet beim Cursor immer eine Laufvariable, die einer Struktur entspricht und die bei Bedarf automatisch angelegt wird. Letzteres knnen Sie aber auch durch eine eigene Deklaration vorwegnehmen. Ansonsten mssen Sie bei dieser Art der Verarbeitung eigentlich nur noch beachten, dass der Cursor beim Einstieg in die Schleife nicht geffnet sein darf, da das ansonsten zu einem Laufzeitfehler fhrt. Parameter in Cursorn verwenden Die bisher in unserem Cursor verwendete Abfrage war stets statisch und besa keine laufzeitabhngige Komponente. Eine solche knnen Sie natrlich hnlich wie bei der zuvor gezeigten einfachen Abfrage erzeugen, indem Sie innerhalb der Abfrage einfach andere Variablen verwenden.
declare xpersnr personalien.persnr%type; cursor read_pers is select name from personalien where persnr = xpersnr;

Wird dieser Cursor whrend der Programmausfhrung geffnet, dann richtet sich das Abfrageergebnis nach dem aktuellen Wert der Variablen xpersnr. So weit so gut, und trotzdem hat das soeben beschriebene Verfahren entscheidende Nachteile. Zum einen mssen die beim Cursor verwendeten Variablen alle vorab definiert werden, d.h. schon im Deklarationsteil Ihres Programms entstehen nicht immer angenehme Abhngigkeiten. Zum anderen verdient dieses Verfahren auch nicht gerade einen bersichtspreis. Wird der Cursor beispielsweise einige hundert Zeilen spter verwendet, dann ist nirgendwo ersichtlich, ob und mit welchen Parametern die zugehrige Abfrage ausgefhrt wird. Besser wre es, die bentigten Variablen beim Starten des Cursors als sichtbare Parameter zu bergeben, wozu es in PL/SQL ein entsprechendes Verfahren (vgl. Listing 5.13) gibt.
declare cursor read_pers(xpersnr varchar2) is select name from personalien where persnr = xpersnr; begin for xrec in read_pers('7000188') loop dbms_output.put_line(xrec.name); end loop; end;
Listing 5.13: Parameterbergabe an einen Cursor

Einfhrung in PL/SQL

423

Ich finde, dass der ganze Aufbau jetzt stark an eine Funktion erinnert. Bei der Definition des Cursors werden alle bentigten Variablen zusammen mit ihrem Datentyp hinter dem Cursornamen in Klammern aufgelistet und beim Starten bzw. ffnen des Cursors werden dann alle konkreten Werte wie bei einem Funktionsaufruf in der entsprechenden Reihenfolge bergeben. Dynamisches SQL Die zuletzt verwendeten Abfragen waren zum Schluss zwar alle in einem gewissen Umfang variabel, doch verdient keine der bisherigen Beispiele die Bezeichnung dynamisches SQL. Hierunter versteht man im Allgemeinen etwas ganz anderes, nmlich die Mglichkeit die gesamte SQL-Abfrage erst zur Laufzeit zusammenzubauen und anschlieend auszufhren. Nehmen wir als Aufgabenstellung einmal an, wir mchten von Zeit zu Zeit alle Indices unseres Schemas reorganisieren. Grundstzlich ist so eine Indexreorganisation mit Hilfe einer Anweisung gem dem folgenden Schema mglich:
alter index <Indexname> rebuild;

Auerdem erhalten Sie alle im Schema enthaltenen Indices durch eine Abfrage der View user_indexes, doch wie kann man diese Informationen zusammen mit der jeweils entsprechenden alter index-Anweisung dynamisch kombinieren. Wenn man es nicht besser wei, dann kann man sich natrlich mit Hilfe einer entsprechenden Anweisung die zur Reorganisation bentigten Statements erzeugen und das hierdurch ausgegebene Skript in einem zweiten Schritt ausfhren.
select 'alter index ' || index_name || ' rebuild;' from user_indexes

Da PL/SQL Ihnen aber die Mglichkeit bietet, zur Laufzeit generierte SQL-Kommandos auszufhren, knnen wir diese beiden Schritte auch in einem verschmelzen und uns hierfr ein entsprechendes Skript basteln. Die Basis fr die Verwendung dynamischer SQL-Abfragen finden Sie im Paket dbms_sql, das in der Oracle-Dokumentation wieder im Buch Oracle8 Application Developer's Guide beschrieben ist. Wenn wir zunchst einmal von Auswahlabfragen absehen, dann folgt die Verwendung dynamischer SQL-Statements dem folgenden Schema: ffnen eines Ausfhrungskanals mit Hilfe der Funktion open_cursor. Prfen des auszufhrenden Statements mit Hilfe der Prozedur parse. Beachten Sie, dass DDL-Statements hierbei auch sofort ausgefhrt werden. Auf der anderen Seite schadet es aber auch nicht, wenn Sie jedes Mal eine execute-Funktion verwenden, da das geparste DDL-Statement nicht noch einmal ausgefhrt wird. Ausfhren der Abfrage durch einen Aufruf der execute-Funktion. Schlieen des Ausfhrungskanals durch einen Aufruf der Prozedur close_cursor.

: : : :

424

PL/SQL-Programmierung

Die vollstndige Lsung der oben beschriebenen Aufgabe finden Sie im Listing 5.14. Zunchst einmal definieren wir in diesem Programm den Cursor meine_indexe entsprechend der eben dargestellten Abfrage auf die View user_indexes. Des weiteren bentigen wir im Programm noch zwei weitere Integervariablen sql_id und ret. Zentralstelle des Programms ist die for loop-Schleife, in der alle vom Cursor gelieferten Indexnamen der Reihe nach geliefert und mit Hilfe der Variablen mi_rec. index_name zur Verfgung gestellt werden.
declare cursor meine_indexe is select index_name from user_indexes; sql_id integer; ret integer; begin sql_id := dbms_sql.open_cursor; for mi_rec in meine_indexe loop dbms_sql.parse(sql_id, 'alter index ' || mi_rec.index_name || ' rebuild', dbms_sql.native); -- wegen des DDL-Befehls ist ein execute -- nicht unbedingt notwendig -- ret := dbms_sql.execute(sql_id); end loop; dbms_sql.close_cursor(sql_id); end;
Listing 5.14: Reorganisation aller Indices mit Hilfe dynamischer SQL-Anweisungen

Vor dem Einstieg in die Schleife erffnen wir einen dynamischen SQL-Cursor, indem wir die Funktion open_cursor aufrufen.
sql_id := dbms_sql.open_cursor;

Den von dieser Funktion zurckgegebenen Wert speichern wir in einer Variablen, da er fr alle weiteren dynamischen Aktivitten bentigt wird. Innerhalb der Schleife wird das auszufhrende Statement zunchst geprft, indem es der parseProzedur bergeben wird, was prinzipiell nach folgendem Schema geschieht:
dbms_sql.parse(<Cursor-Id>, <Statement>, <Spracheinstellung>)

Wie Sie sehen, bentigt diese Prozedur insgesamt drei Parameter. Der erste dieser drei Parameter spezifiziert dabei den zuvor geffneten Cursor, d.h. hier mssen Sie den von der open_cursor-Funktion gelieferten Wert bergeben. Der zweite Parame-

Einfhrung in PL/SQL

425

ter enthlt die auszufhrende Abfrage und mit dem letzten Parameter legen Sie die bei der Prfung zu verwendende PL/SQL-Sprachversion fest. Hierzu existieren im dbms_sql-Paket drei vordefinierte Werte, die Sie der Tabelle 5.12 entnehmen knnen.
Konstante V6 V7 Native Wert 0 2 1 Bedeutung Interpretation des Statements entsprechend der Version 6. Verwenden der Version 7. Aktuelle Version zur Statementanalyse benutzen.

Tabelle 5.12: Sprachoptionen der dbms_sql.parse

Nach der erfolgreichen Analyse des auszufhrenden Statements kann dieses mit Hilfe der execute-Funktion ausgefhrt werden, die hierzu lediglich die Kennung des zugehrigen Cursors bentigt. Der von dieser Funktion zurckgegebene Wert enthlt bei nderungsabfragen die Anzahl der von der Abfrage betroffenen Datenstze und bei Auswahlabfragen ist dieser Wert ohne Bedeutung.
ret := dbms_sql.execute(sql_id);

Zum Schluss mssen Sie den Cursor wieder schlieen, was diesmal mit Hilfe der close_cursor-Prozedur passiert, der Sie zu diesem Zwecke wieder die entsprechende Cursorkennung bergeben mssen.
dbms_sql.close_cursor(sql_id);

Wie Sie an dem letzten Beispiel gesehen haben, war es gar nicht so schwer, mit Hilfe des dbms_sql-Pakets ein intelligentes Skript zu erstellen, das bestimmte Wartungsarbeiten durchfhrt. Solche und hnliche Arbeiten lassen sich in der Praxis wirklich prima mit Hilfe dynamischer SQL-Statements erledigen, weshalb Routinen in der eben beschriebenen Form hufig anzutreffen sind. Allerdings ist der Leistungsumfang des dbms_sql-Pakets noch wesentlich grer, denn neben dem Ausfhren von DDL- oder DML-Anweisungen lassen sich auch Auswahlabfragen dynamisch erzeugen und ausfhren. Dynamische Auswahlabfragen erstellen Wie Sie gleich sehen werden, ist die Erstellung dynamischer Auswahlabfragen ein ganz schnes Stck Tipparbeit. Mit Hilfe einer dynamischen Auswahlabfrage wollen wir verschiedene Felder aus den Personalien und den zugehrigen Gehltern aus der Datenbank lesen und diese am Bildschirm ausgeben. Die dabei verwendete Abfrage beinhaltet also eine Verknpfung zwischen den Tabellen personalien und gehalt, wobei die Gehaltsdaten zustzlich auf den aktuellsten Datensatz eingeschrnkt werden sollen. Wir haben es in unserem Beispiel konkret also mit folgender Abfrage zu tun:
select a.persnr, a.name, a.gebdatum, b.gehalt from personalien a, gehalt b where b.persnr = a.persnr and b.gab = (select max(gab)

426

PL/SQL-Programmierung

from gehalt b1 where b1.persnr = b.persnr ) order by a.name

Das komplette Programm finden Sie im Listing 5.15, das wir im Anschluss mal wieder Stck fr Stck auseinandernehmen werden und selbst wenn Sie dynamische Auswahlabfragen in der Regel nur sehr selten bentigen, so ist das Beispiel doch wenigstens dazu geeignet aufzuzeigen, wie einfach doch die Verwendung eines deklarierten Cursors ist.
declare dyn_sql integer; sql_st varchar2(500); rc integer; xpersnr xname xgeburt xgehalt begin dbms_output.enable(50000); dyn_sql := dbms_sql.open_cursor; sql_st := 'select a.persnr, a.name, a.gebdatum, b.gehalt from personalien a, gehalt b where b.persnr = a.persnr and b.gab = (select max(gab) from gehalt b1 where b1.persnr = b.persnr ) order by a.name'; dbms_sql.parse(dyn_sql, sql_st, dbms_sql.native); dbms_sql.define_column(dyn_sql, dbms_sql.define_column(dyn_sql, dbms_sql.define_column(dyn_sql, dbms_sql.define_column(dyn_sql, 1, 2, 3, 4, xpersnr, 10); xname, 30); xgeburt); xgehalt); varchar2(10); varchar2(30); date; number;

rc := dbms_sql.execute_and_fetch(dyn_sql); while rc > 0 loop dbms_sql.column_value(dyn_sql, 1, xpersnr); dbms_sql.column_value(dyn_sql, 2, xname); dbms_sql.column_value(dyn_sql, 3, xgeburt); dbms_sql.column_value(dyn_sql, 4, xgehalt);

Einfhrung in PL/SQL

427

dbms_output.put(rpad(xpersnr,10,' ') || ' '); dbms_output.put(rpad(xname,30,' ') || ' '); dbms_output.put(to_char(xgeburt, 'DD.MM.YYYY') || ' '); dbms_output.put(to_char(xgehalt,'999990.00' )); dbms_output.new_line; rc := dbms_sql.fetch_rows(dyn_sql); end loop; dbms_output.put_line('Anzahl Stze: ' || to_char(dbms_sql.last_row_count,'9999')); dbms_sql.close_cursor(dyn_sql); end;
Listing 5.15: Beispiel einer dynamischen Auswahlabfrage

Eigentlich beginnt alles genau wie bei den dynamischen nderungsabfragen, d.h. zunchst erzeugen wir uns wieder einen dynamischen Cursor, dessen Kennung wir in der Variablen dyn_sql speichern. Die auszufhrende Abfrage konstruieren wir in der Variablen sql_st und bergeben sie anschlieend der Prozedur parse zur berprfung und Wrdigung. Erst was danach kommt ist im Vergleich zum vorhergehenden Beispiel wirklich neu.
dbms_sql.define_column(dyn_sql, 1, xpersnr, 10); dbms_sql.define_column(dyn_sql, 3, xgeburt);

Mit Hilfe der define_column-Prozedur mssen Sie diejenigen Spalten der Abfrage definieren, die Sie nach dem Lesen der einzelnen Datenstze in entsprechende Variablen bernehmen wollen. Dank der berlagerungstechnik knnen dabei nahezu alle Datentypen mit Hilfe der gleichen Prozedur definiert werden, die dafr drei bis vier Parameter erwartet. Durch den ersten Parameter wird der Bezug zum definierten Cursor hergestellt, indem die zugehrige Kennung bergeben wird. Der zweite Parameter bezieht sich auf die in der select-Anweisung aufgezhlten Spalten und Ausdrcke und beschreibt die entsprechende Position in dieser Liste. Mit Hilfe des dritten Parameters legen Sie die Variable fest, in der die selektierten Werte spter bereitgestellt werden sollen. Bei numerischen Werten oder Datumsfeldern sind Sie damit auch schon fertig und nur bei Textfeldern mssen Sie mit Hilfe des vierten Parameters die gewnschte Lnge des Textpuffers vorgeben. Die define_column-Prozedur ist also das Bindeglied zwischen der Abfrage auf der einen und den entsprechenden Programmvariablen auf der anderen Seite. Nachdem Sie nun die Verbindung zwischen dem Abfrageobjekt und Ihren Programmvariablen hergestellt haben, knnten Sie die in dem Cursor gespeicherte Abfrage ausfhren, was wiederum mit Hilfe der execute-Funktion mglich wre. Der nchste Schritt bestnde dann darin, denn ersten Datensatz aus der selektierten Datenmenge anzufordern.

428

PL/SQL-Programmierung

Da diese beiden Schritte in Auswahlabfragen eigentlich immer zusammengehren, gibt es dafr im dbms_sql-Paket sogar eine eigene Funktion, die wir in unserem Beispiel auch verwendet haben.
rc := dbms_sql.execute_and_fetch(dyn_sql);

Mit der Funktion execute_and_fetch wird also die Abfrage ausgefhrt und der erste Datensatz, sofern vorhanden, wird zur Abholung bereitgestellt. Hierzu bentigt die Funktion wiederum die Kennung des geffneten Cursors und liefert als Ergebnis die Zahl der gelesenen Datenstze zurck, d.h. sofern Ihre Abfrage gar keine Stze ermitteln konnte, erhalten Sie hier als Wert die Zahl 0. Alle weiteren Datenstze werden mit Hilfe der fetch_rows-Funktion angefordert, die wiederum die Zahl der gelesenen Stze zurckliefert und die Cursorkennung als Parameter bergeben bekommt.
rc := dbms_sql.fetch_rows(dyn_sql);

Aufgrund der Verhaltensweise dieser beiden Funktionen knnen Sie das Abarbeiten der selektierten Datenmenge ganz gut mit einer while loop-Schleife programmieren, die insgesamt so lange durchlaufen wird, wie der von der fetch_rows-Funktion zurckgegebene Wert grer 0 ist.
rc := dbms_sql.execute_and_fetch(dyn_sql); while rc > 0 loop ... rc := dbms_sql.fetch_rows(dyn_sql); end loop;

Innerhalb der Schleife mssen wir nun bei jedem Durchlauf und damit fr jeden selektierten Datensatz die einzelnen gewnschten Spalten anfordern, was mit Hilfe der column_value-Prozedur passiert, die hierzu neben der Cursorkennung wieder die Position der Select-Liste und die zugehrige Programmvariable bentigt.
dbms_sql.column_value(dyn_sql, 1, xpersnr);

Die restlichen Befehle innerhalb der Schleife dienen zur Aufbereitung bzw. Formatierung der gelesenen Werte, beispielweise werden die Textfelder mit Hilfe der rpadFunktion auf eine einheitliche Lnge ausgerichtet, so dass Endergebnis der normalen Ausgabe im SQL-Editor in fast nichts nachsteht. Am Ende der ausgegebenen Datenstze drucken wir sogar noch die Zahl der gelesenen Datenstze aus, die wir mit Hilfe der last_row_count-Funktion ermitteln knnen. Diese Funktion entspricht praktisch der rowcount-Statusvariablen, die Sie bei den statischen Cursorn kennen gelernt haben, d.h. der von der Funktion last_row_count gelieferte Wert erhht sich wieder mit jedem erfolgreichen Aufruf von fetch_rows.
7000006 7000018 7000021 ... Beckmann,Yonne Bruckner,Yonne Btzing,Brbel 04.01.1957 13.03.1968 17.01.1963 5899.00 5300.00 624.00

Einfhrung in PL/SQL

429

7000012 Sistermann,Willy 7000016 Voltair,Samuel 7000008 Voltair,Samuel 7000009 Zola,Wolf Anzahl Stze: 23

16.08.1975 23.01.1959 19.11.1965 23.07.1966

5122.00 6300.00 5200.00 6200.00

Listing 5.16: Ausfhrung der dynamsichen Auswahlabfrage aus Beispiel 5.15

Dynamische Abfragen parametrieren In diesem nun folgenden letzten Abschnitt zum Thema der Abfrageverwendung in einem PL/SQL-Programm werden wir die bisherigen Verfahrensweisen krnen und unsere dynamischen Abfragen parametrieren. Wenn Sie sich nun fragen, warum bzw. aus welchem Grund wir irgendwelche Mhen unternehmen, die dynamischen Abfragen in einem nun folgenden Schritt noch flexibler zu gestalten, dann gibt es hierfr eine ganz einfache Antwort, nmlich Zeit. Wird innerhalb eines Programms eine dynamische Abfrage zum Beispiel innerhalb einer Schleife mehrfach mit lediglich anderen Parametern ausgefhrt, so knnen Sie sich den mehrfachen Aufruf der parse-Prozedur und die damit verbundenen Prfungen und bersetzungsaktivitten sparen, indem Sie die Abfrage parametergesteuert erstellen. Dabei mssen Sie fr jeden bentigten Parameter in der dynamischen SQL-Anweisung einen entsprechenden Platzhalter definieren.
dbms_sql.parse(sql_id, 'delete lohnarten where persnr = :X', dbms_sql.native);

Fr diese Platzhalter knnen Sie hnliche wie bei den Variablen einem beliebigen Namen verwenden, wobei die Kennzeichnung des Platzhalters durch einen vorangestellten Doppelpunkt erfolgt. Vor dem Ausfhren der Abfrage, d.h. vor dem Ausfhren der execute- bzw. execute_and_fetch-Funktion mssen Sie den Platzhalter natrlich durch einen konkreten Wert ersetzen, wofr die bind_variable-Prozedur im dbms_sql-Paket existiert.
dbms_sql.bind_variable(sql_id, ':X', xpersnr);

Mit Hilfe dieser Prozedur wird der in der Abfrage vorhandene Platzhalter :X, dessen Name als zweiter Parameter spezifiziert werden muss durch den als dritten Parameter bergebenen Wert ersetzt. In meinem Beispiel wrde also der in der Variablen xpersnr gespeicherte Wert in die Lschabfrage eingesetzt, so dass das anschlieende Ausfhren der execute-Funktion zur Lschung der entsprechenden Mitarbeiterdaten fhrt.

5.1.9

Fehlerbehandlung

Tritt whrend der Ausfhrung eines PL/SQL-Programms ein Fehler auf, so wird das Programm mitsamt der aktuellen Transaktion abgebrochen. Dabei ist es relativ gleichgltig, wie es zu der Fehlersituation kam bzw. was den Laufzeitfehler ausge-

430

PL/SQL-Programmierung

lst hat. Im Folgenden finden Sie eine bei weitem nicht vollstndige Liste von mglichen Ursachen solcher Laufzeitfehler:

: :

Es liegt eine technische Strung vor. Beispielsweise ist eine an der Abfrage beteiligte Datenbank nicht verfgbar, das verwendete Rollback-Segment ist zu klein, oder Tablespace oder die zugehrige Festplatte ist voll. Manchmal liegen die Ursachen eines Laufzeitfehlers auch im Betriebsablauf, beispielweise weil bestimmte Datenbankobjekte aufgrund von Zugriffskonflikten nicht gesperrt werden konnten oder weil ein Administrator die zum Programm gehrende Session wegen anlaufender Wartungsarbeiten aus dem System geworfen hat. Ein anderer Pulk von Quellen fr Laufzeitfehler ist eher im zugehrigen Programm zu suchen. Hierzu zhlen beispielsweise Situationen, in denen nicht definierte (z.B. Division durch 0) oder verbotene Anweisungen (Zuweisung von null in eine not null-Variable) ausgefhrt werden. Ebenfalls in diese Kategorie gehren Probleme, die beim Einsatz dynamischer SQL-Anweisungen entstehen, weil die zur Laufzeit konstruierten SQL-Abfragen syntaktisch fehlerhaft sind. Die letzte und wesentlichste Gruppe von Fehlerursachen ist allerdings in dem ganz gewhnlichen Betrieb einer relationalen Datenbank und der damit verbundenen Methoden und Konzepte zu suchen. Was kann der arme Programmierer dafr, wenn seine eigentlich korrekte SQL-Anweisung von irgendeinem Constraint oder Trigger zurckgerollt wird oder wenn ein Datensatz aufgrund der Mehrbenutzerumgebung auf einmal schon da ist und wegen des vorhandenen Primrschlssel ein Laufzeitfehler des Typs doppelter Wert bei einem eindeutigen Index entsteht?

Die Frage, die Sie sich bei jedem Programm oder Skript nun stellen mssen ist, welcher dieser eben genannten Laufzeitfehler wollen Sie in Ihrem Programm explizit abfangen und bei welchen Fehler lassen Sie es einfach drauf ankommen und nehmen somit im Falle eines Falles eben den Programmabsturz in Kauf. Nach meiner Ansicht kann man die aus den beiden ersten Gruppen resultierenden Laufzeitfehler oftmals durchaus unbeachtet lassen, d.h. beim Eintreten einer solchen Situation erfolgt ein entsprechender Programmabsturz. Eigentlich ist es ja egal, ob die Meldung eines technischen Problems durch eine Systemmeldung oder mit Hilfe einer im Programm generierten Meldung erfolgt. Auerdem gibt es gerade im technischen Umfeld Fehlersituationen, die keine Fehlerbehandlungsroutine dieser Welt erfolgreich behandeln kann, beispielsweise wenn der Datenbankserver einfach ausgeschaltet wurde. Fr die in der dritten Gruppe beschriebenen Fehlerquellen finde ich auch nicht unbedingt, dass sie in einer speziellen Fehlerbehandlungsroutine gut aufgehoben sind, denn die meisten solcher Probleme knnen schon im Vorfeld durch entsprechende Programmpassagen abgefangen bzw. ausgeschlossen werden. Besteht beispielsweise die Mglichkeit, dass ein Divisor den Wert 0 annehmen kann, dann sollte das im Vorfeld der Division durch entsprechende Programmlogik abgefangen werden. Besteht diese Mglichkeit aufgrund der vorhandenen Rahmenbedingungen eigentlich nicht, so kann man in vielen Fllen auch ohne Prfung und speziel-

Einfhrung in PL/SQL

431

ler Fehlerbehandlungsroutine in die Divisionsaufgabe einsteigen. Steht dann doch einmal eine 0 unter dem Bruchstrich, so fhrt das halt zum vorzeitigen Ableben Ihres Programms und der Erkenntnis, dass ein Fehler im Gesamtkonzept vorliegt bzw. die nicht 0 Garantie nicht viel Wert war. Die in der letzten Gruppe beschriebenen Fehlerursachen sollten im Regelfall sicherlich nicht zum Absturz eines Programms, sondern hchstens zum Abbruch der aktuellen Transaktion und zur Ausgabe entsprechender Meldungen fhren, wobei es natrlich auch hier Situationen gibt, wo das Versagen einer Operationen den geordneten Rckzug des gesamten Programms nahe legt. Behandlung im Programm Wie ich schon ganz am Anfang des Kapitels angedeutet habe, besteht innerhalb von PL/SQL die Mglichkeit, innerhalb eines Programmblocks eine spezielle Routine zur Behandlung von Laufzeitfehlern zu programmieren. Eine solche Fehlerbehandlungsroutine beginnt mit dem Schlsselwort exception und bildet meistens den Abschluss eines solchen Programmblocks, so dass sich fr die Blockstruktur unserer Programme das folgende neue Schema ergibt:
begin ... Anweisungen des Blocks A begin ... Anweisungen des Blocks B exception ... Fehlerbehandlung fr Block B end; exception ... Fehlerbehandlung fr Block A end;

Diesem Schema knnen Sie auch entnehmen, dass durch die geeignete Konstruktion von Programmblcken die Mglichkeit besteht, fr spezielle Anweisungen entsprechende Fehlerbehandlungsroutinen zu programmieren. Das ist gerade bei der Erstellung von Schleifen besonders interessant, wenn bei einem Fehler innerhalb der Schleife zwar der aktuelle Datensatz nicht weiter bearbeitet werden soll, die noch fehlenden Durchlufe bzw. die restlichen Datenstze jedoch verarbeitet werden knnen. Wie gesagt, beginnt die Programmierung einer solchen Ausnahmeroutine mit der exception-Anweisung, der mit Hilfe des Schlsselwortes when eine Aufzhlung der zu bercksichtigenden Ausnahmezustnde folgt, so dass sich folgendes Programmschema ergibt:
exception when Laufzeitfehler-A then ... Problembehandlung fr A

432

PL/SQL-Programmierung

when Laufzeitfehler-B then ... Problembehandlung fr B ... when others then

Die zu verwendenden Codes sind im Paket dbms_standard vordefiniert, so dass Sie in Ihrem Programm die dort definierten Konstanten und damit sprechende Namen verwenden knnen. Eine vollstndige Aufstellung der verfgbaren Konstanten mssen Sie jetzt allerdings nicht dem dbms_standard-Paket entlocken, sondern Sie finden diese in der Oracle-Dokumentation im Buch PL/SQL User's Guide and Reference im Kapitel Error Handling und dort im Abschnitt Predefined Exceptions. Ist der aufgetretene Fehler in Ihrer selbstgeschriebenen Fehlerbehandlungsroutine nicht enthalten, dann tritt wieder das dafr im System standardmig verfgbare Verfahren in Kraft, d.h. es erfolgt die Ausgabe der zugehrigen Hinweis- bzw. Fehlermeldungen und anschlieend kommt es zum erzwungenen Progra