Hallo, mein Name ist Jens Lambert.
In diesem Video zeige ich Ihnen, wie Sie mit dem SQL Developer
von Oracle PL/SQL Anweisungen und Programme schreiben,
bearbeiten und ausführen können.
Außerdem werden wir uns ansehen, wie im SQL Developer
bei der Fehlersuche vorgegangen werden kann.
Als Beispiel verwenden wir die Umsetzung
eines einfachen Kassensystems eines Möbelkaufhauses.
Wir beginnen
mit einer geöffneten Session an einem Oracle Datenbank Server.
Die Konsolen Ausgabe kann auf zwei verschiedene Arten aktiviert werden.
Zum Testen führen wir eine einzige Anweisung mit EXECUTE aus.
Diese soll auf der Konsole den Text "Hallo Welt" ausgeben.
Allerdings sehen wir nur, dass die Anweisung ausgeführt wurde.
Was ausgeführt wurde, wird nicht angezeigt.
Um die Konsolen Ausgabe für die verwendete Session
zu aktivieren, kann der Skript Befehl SET SERVEROUTPUT ON dem
ersten Befehl vorangestellt werden.
Nun wird die Ausgabe
auch in der Konsole angezeigt.
Als Alternative bietet der SQL Developer auch die Möglichkeit an,
einen zusätzlichen Bereich
für die Ausgabe von Meldungen des Servers anzulegen.
Dazu findet man im Menü Ansicht
den Eintrag DBMS Ausgabe. Im neu angezeigten Bereich
muss dann mit dem grünen Plus Symbol eine Verbindung
zur verwendeten Datenbank hergestellt werden.
Die Ausgabe teste ich nun mit einem anonymen Block,
der mehrere Anweisungen beinhalten kann.
Die Sequenz aus vier Anweisungen erzeugt
eine Ausgabe in zwei Zeilen im Ausgabe Bereich.
Erst wenn nach mehreren Aufrufen PUT_LINE aufgerufen wird,
wird die Zeile abgeschlossen und eine neue Zeile
begonnen.
Für die Arbeit
mit PL/SQL habe ich zwei Tabellen vorbereitet,
die in vereinfachter Form
das Kassensystem eines Möbel- kaufhauses darstellen sollen.
Es gibt eine Tabelle für die Artikel, in der ein paar Möbel
mit Artikelnummer, Bezeichnung und im Netto-Einkaufs-
und Verkaufspreis je Stück gespeichert sind.
Damit kein Artikel unter dem Einkaufspreis verkauft wird,
integriere ich einen passenden Check-Constraint.
Jetzt noch ein paar Möbelstücke in die Tabelle eingefügt
und fertig ist unser kleiner Möbelkatalog.
Um die Verkäufe zu dokumentieren, benötige ich eine Art Kassensystem.
Die eindeutige Beleg Nummer, die auch als Primärschlüssel verwendet wird,
generiere ich mit einer SEQUENCE.
In der Tabelle Verkäufe
sollen die verkauften Artikel anhand
der Artikelnummer mit ihrer Anzahl registriert werden.
Der vom Käufer gezahlte Preis wird auch dokumentiert.
Bevor etwas verkauft werden kann, interessiert den Kunden natürlich
der Verkaufspreis auf dem Preisschild.
Weil in der Artikel Tabelle lediglich der
Nettoverkaufspreis ausgewiesen wird,
benötige ich für die spätere Bezahlung noch eine Funktion,
die mir den Verkaufspreis mit Mehrwertsteuer
und dem möglichen Rabatt berechnet.
Das bereite ich zunächst in einem anonymen Block vor.
Zuerst werden unter DECLARE lokale Variablen
für den Nettoverkaufspreis
und den möglichen Rabatt in Prozent definiert.
Außerdem wird noch eine Konstante für die Mehrwertsteuer angelegt.
Im ausführbaren Abschnitt
brauchen wir eine Abfrage, die uns von der Artikelbezeichnung
oder Artikelnummer den zugehörigen Nettoverkaufspreis ermittelt.
Dieser wird dann in einer lokalen Variablen gespeichert,
mit den Faktoren für Rabatt und Mehrwertsteuer ausmultipliziert
und auf zwei Nachkommastellen gerundet ausgegeben.
Wird der anonyme Block ausgeführt, kommt es zu einer Fehlermeldung:
"ID Nettoverkaufspreis muss deklariert werden."
Die Zeilen Nummer des Fehlers bezieht sich hier
auf den Fundort des Fehlers ab Beginn der Anweisung oder Markierung.
In der SQL-Abfrage gibt es den Nettoverkaufspreis allerdings
nur als Attribut einer Relation, nicht als lokale Variable.
Im Deklarationsabschnitt finden wir jedoch eine gleichnamige
lokale Variable mit dem Präfix l_.
Eine Deklaration der Variable hat also stattgefunden,
nur wurde hier das Präfix l_ vergessen.
Das trage ich nun nach.
Ein erneutes Ausführen erzeugt
nun eine weitere Fehlermeldung: "Keine Daten gefunden."
Anhand der Zeilen Nummer ist erkennbar,
dass es sich hier um einen SQL-Abfrage Fehler handelt
und die Abfrage ein leeres Ergebnis zurückgibt.
Ich korrigiere das, indem
ich eine Artikelnummer eintrage, die in der Relation vorhanden ist.
Jetzt wird der erwartete Verkaufspreis ausgegeben.
Damit dieses Programm leicht von einer
Anwendung aufgerufen werden kann, soll es als STORED FUNCTION in der
Datenbank als Funktion Verkaufspreis gespeichert werden.
Nun deklariere ich die Funktion zur Ermittlung des Verkaufspreises
mit der Signatur CREATE OR REPLACE FUNCTION Verkaufspreis.
Als Übergabe Parameter definiere ich die Artikelnummer
mit in_artikelnummer IN NUMBER und den prozentualen
Rabatt mit in_rabatt IN NUMBER.
Den deklarativen Abschnitt übernehme ich aus dem zuvor
erstellten anonymen Block und passe den Rabatt entsprechend an.
Dabei fällt auf, dass
die lokale Variable für den Nettoverkaufspreis
mit einem Syntax Fehler markiert wird.
Weil es keine genaueren Angaben zum Fehler gibt, fahre ich zunächst
fort.
Den Programmcode übernehme ich auch und führe die Funktion zum Test aus.
Diesmal wird der Programmcode jedoch nicht wie der anonyme Block
ausgeführt, sondern kompiliert und in der Datenbank gespeichert.
Dabei werden wir auf den folgenden Fehler hingewiesen:
"Fand das Symbol l_nettoverkaufspreis
als eines der folgenden erwartet wurde: return."
Die angezeigten Zeilen und Spalten Nummern des Fehlers beziehen
sich jetzt im "Compiler-Log" auf das SQL-Skript und in der
Skript Ausgabe auf den Code in der Datenbank.
Wird keine Fehler Beschreibung angezeigt,
kann diese mit SHOW ERRORS aufgerufen werden.
Nach dem Aktualisieren und Öffnen der Funktionen-
Rubrik im Datenbank-Explorer wird die Funktion Verkaufspreis
mit einem weißen X in einem roten Kreis als Fehler markiert.
Mit einem Klick auf
die in der Datenbank gespeicherte Funktion wird der Inhalt angezeigt
und kann bearbeitet werden.
Im Normalfall wird die mit Zeile Spalte angegebene Fehler
Position zusätzlich mit einer roten Markierung gekennzeichnet.
Durch die Fehlermeldung ist nun klar, dass hier vor ein RETURN
mit dem Typ des Funktions-Rückgabe- wertes eingefügt werden muss.
Im SQL-Skript beseitige ich den Fehler,
gebe RETURN NUMBER AS ein
und kompiliere erneut.
Nach dem Aktualisieren verschwindet die Fehler
Markierung an der Funktion.
Um sicherzugehen, dass die Funktion fehlerfrei ist, kann im
Kontextmenü: "Für Debug kompilieren" angeklickt werden.
Ein grüner Punkt auf dem Funktionsnamen zeigt
nun an, dass es keine Compiler- Fehler mehr gibt.
Der Fehler kann auch direkt in der Datenbank korrigiert werden
und mit dem Zahnrad Symbol erneut kompiliert werden.
Das birgt
aber die Gefahr, dass die Korrektur im SQL-Skript vergessen wird
und so später durch erneutes ausführen des Skripts verworfen wird.
Zum Test der Funktion führe ich eine kurze Verkaufspreisabfrage
in einem anonymen Block aus und erhalte erneut eine Fehlermeldung
"PL/SQL: Funktion hat keinen Wert zurückgegeben."
Es wird also kein Wert von der Funktion zurückgegeben.
Dann sehe ich in der Datenbank gespeicherten Funktion nach
und stelle fest, dass das abschließende RETURN fehlt,
wo jetzt noch eine Ausgabe aufgerufen wird.
Im SQL-Skript ergänze ich an der Stelle RETURN
und reduziere die Textausgabe auf die Rückgabe einer Zahl,
damit der Übergabe-Typ stimmt und kompilierte erneut.
Der Test
der Funktion gibt jetzt wie gewünscht den Verkaufspreis aus.
Anstatt mit einem anonymen Block kann das
Ergebnis nun auch mit einem SQL- Query ausgegeben werden.
Der Verkauf eines Artikels
wird nun mit einer Prozedur abgebildet,
die als Parameter die Bezeichnung und Anzahl des verkauften Artikels
sowie den gewährten Rabatt übergeben bekommt.
Die Beleg Nummer wird von einer SEQUENCE eindeutig generiert.
Die Artikelnummer wird anhand der Artikelbezeichnung aus der Artikel
Tabelle geholt.
Dabei wird das einelementige Ergebnis der Abfrage mit dem Schlüsselwort
INTO in die Variable l_artikelnummer gespeichert.
Um den Verkauf zu dokumentieren,
wird in der Tabelle Verkäufe persistiert.
Dazu verwende ich die generierte Belegnummer,
die ermittelte Artikelnummer, die übergebene Anzahl
und den durch die Funktion errechneten Verkaufspreis pro Stück,
der noch mit der Anzahl multipliziert wird,
um die Endsumme des Einkaufs zu erhalten.
Ist diese Prozedur nun kompiliert, können einzelne
Artikel verkauft werden.
Dazu führe ich für jeden verkauften Artikel die Prozedur verkaufen aus
und übergebe ihr
die Artikelbeschreibung, die Anzahl und den gewährten Rabatt.
Um Verkäufe noch mit einem ROLLBACK stornieren zu können,
beende ich den Einkauf mit einem COMMIT.
Zum Schluss
noch einen Blick auf die in der Datenbank abgelegten Verkäufe.
Dazu verwende ich eine Abfrage, in der die Relationen
Artikel und Verkäufe mit einem Natural Join verknüpft werden
und die erfassten Daten formatiert ausgegeben werden.
So sehen wir eine schöne Auflistung aller verkauften
Möbel mit dem erzielten Verkaufsergebnis.
Vielen Dank für's Zusehen.
Bis zum nächsten Mal.