1 00:00:00,016 --> 00:00:02,399 Hallo, mein Name ist Jens Lambert. 2 00:00:02,399 --> 00:00:05,749 In diesem Video zeige ich Ihnen, wie Sie mit dem SQL Developer 3 00:00:05,749 --> 00:00:10,016 von Oracle PL/SQL Anweisungen und Programme schreiben, 4 00:00:10,016 --> 00:00:12,899 bearbeiten und ausführen können. 5 00:00:12,899 --> 00:00:15,349 Außerdem werden wir uns ansehen, wie im SQL Developer 6 00:00:15,349 --> 00:00:18,049 bei der Fehlersuche vorgegangen werden kann. 7 00:00:19,099 --> 00:00:21,499 Als Beispiel verwenden wir die Umsetzung 8 00:00:21,499 --> 00:00:24,599 eines einfachen Kassensystems eines Möbelkaufhauses. 9 00:00:25,433 --> 00:00:25,966 Wir beginnen 10 00:00:25,966 --> 00:00:29,449 mit einer geöffneten Session an einem Oracle Datenbank Server. 11 00:00:30,149 --> 00:00:33,982 Die Konsolen Ausgabe kann auf zwei verschiedene Arten aktiviert werden. 12 00:00:34,666 --> 00:00:37,949 Zum Testen führen wir eine einzige Anweisung mit EXECUTE aus. 13 00:00:38,716 --> 00:00:41,716 Diese soll auf der Konsole den Text "Hallo Welt" ausgeben. 14 00:00:42,682 --> 00:00:45,982 Allerdings sehen wir nur, dass die Anweisung ausgeführt wurde. 15 00:00:46,399 --> 00:00:49,199 Was ausgeführt wurde, wird nicht angezeigt. 16 00:00:50,399 --> 00:00:53,066 Um die Konsolen Ausgabe für die verwendete Session 17 00:00:53,066 --> 00:00:58,166 zu aktivieren, kann der Skript Befehl SET SERVEROUTPUT ON dem 18 00:00:58,166 --> 00:00:59,699 ersten Befehl vorangestellt werden. 19 00:01:00,766 --> 00:01:01,316 Nun wird die Ausgabe 20 00:01:01,316 --> 00:01:03,766 auch in der Konsole angezeigt. 21 00:01:05,066 --> 00:01:08,932 Als Alternative bietet der SQL Developer auch die Möglichkeit an, 22 00:01:09,199 --> 00:01:10,649 einen zusätzlichen Bereich 23 00:01:10,649 --> 00:01:13,349 für die Ausgabe von Meldungen des Servers anzulegen. 24 00:01:14,482 --> 00:01:16,432 Dazu findet man im Menü Ansicht 25 00:01:16,432 --> 00:01:21,049 den Eintrag DBMS Ausgabe. Im neu angezeigten Bereich 26 00:01:21,049 --> 00:01:23,665 muss dann mit dem grünen Plus Symbol eine Verbindung 27 00:01:23,665 --> 00:01:25,982 zur verwendeten Datenbank hergestellt werden. 28 00:01:26,632 --> 00:01:29,899 Die Ausgabe teste ich nun mit einem anonymen Block, 29 00:01:30,182 --> 00:01:32,399 der mehrere Anweisungen beinhalten kann. 30 00:01:33,332 --> 00:01:35,632 Die Sequenz aus vier Anweisungen erzeugt 31 00:01:35,632 --> 00:01:38,582 eine Ausgabe in zwei Zeilen im Ausgabe Bereich. 32 00:01:39,749 --> 00:01:43,232 Erst wenn nach mehreren Aufrufen PUT_LINE aufgerufen wird, 33 00:01:43,582 --> 00:01:46,532 wird die Zeile abgeschlossen und eine neue Zeile 34 00:01:46,532 --> 00:01:47,365 begonnen. 35 00:01:49,648 --> 00:01:50,298 Für die Arbeit 36 00:01:50,298 --> 00:01:53,332 mit PL/SQL habe ich zwei Tabellen vorbereitet, 37 00:01:53,332 --> 00:01:54,748 die in vereinfachter Form 38 00:01:54,748 --> 00:01:58,015 das Kassensystem eines Möbel- kaufhauses darstellen sollen. 39 00:01:59,215 --> 00:02:02,665 Es gibt eine Tabelle für die Artikel, in der ein paar Möbel 40 00:02:02,665 --> 00:02:05,748 mit Artikelnummer, Bezeichnung und im Netto-Einkaufs- 41 00:02:05,748 --> 00:02:08,065 und Verkaufspreis je Stück gespeichert sind. 42 00:02:08,848 --> 00:02:11,965 Damit kein Artikel unter dem Einkaufspreis verkauft wird, 43 00:02:12,148 --> 00:02:14,731 integriere ich einen passenden Check-Constraint. 44 00:02:15,798 --> 00:02:18,865 Jetzt noch ein paar Möbelstücke in die Tabelle eingefügt 45 00:02:19,015 --> 00:02:21,448 und fertig ist unser kleiner Möbelkatalog. 46 00:02:22,698 --> 00:02:26,731 Um die Verkäufe zu dokumentieren, benötige ich eine Art Kassensystem. 47 00:02:27,448 --> 00:02:31,248 Die eindeutige Beleg Nummer, die auch als Primärschlüssel verwendet wird, 48 00:02:31,248 --> 00:02:34,698 generiere ich mit einer SEQUENCE. 49 00:02:34,698 --> 00:02:35,365 In der Tabelle Verkäufe 50 00:02:35,365 --> 00:02:38,481 sollen die verkauften Artikel anhand 51 00:02:38,481 --> 00:02:41,148 der Artikelnummer mit ihrer Anzahl registriert werden. 52 00:02:42,081 --> 00:02:45,148 Der vom Käufer gezahlte Preis wird auch dokumentiert. 53 00:02:47,031 --> 00:02:50,364 Bevor etwas verkauft werden kann, interessiert den Kunden natürlich 54 00:02:50,364 --> 00:02:53,481 der Verkaufspreis auf dem Preisschild. 55 00:02:53,481 --> 00:02:55,948 Weil in der Artikel Tabelle lediglich der 56 00:02:55,948 --> 00:02:58,081 Nettoverkaufspreis ausgewiesen wird, 57 00:02:58,081 --> 00:03:01,281 benötige ich für die spätere Bezahlung noch eine Funktion, 58 00:03:01,464 --> 00:03:03,931 die mir den Verkaufspreis mit Mehrwertsteuer 59 00:03:04,081 --> 00:03:06,414 und dem möglichen Rabatt berechnet. 60 00:03:06,414 --> 00:03:09,414 Das bereite ich zunächst in einem anonymen Block vor. 61 00:03:10,281 --> 00:03:13,164 Zuerst werden unter DECLARE lokale Variablen 62 00:03:13,164 --> 00:03:14,881 für den Nettoverkaufspreis 63 00:03:14,881 --> 00:03:17,364 und den möglichen Rabatt in Prozent definiert. 64 00:03:18,198 --> 00:03:22,014 Außerdem wird noch eine Konstante für die Mehrwertsteuer angelegt. 65 00:03:23,331 --> 00:03:24,747 Im ausführbaren Abschnitt 66 00:03:24,747 --> 00:03:28,497 brauchen wir eine Abfrage, die uns von der Artikelbezeichnung 67 00:03:28,497 --> 00:03:32,631 oder Artikelnummer den zugehörigen Nettoverkaufspreis ermittelt. 68 00:03:33,647 --> 00:03:36,631 Dieser wird dann in einer lokalen Variablen gespeichert, 69 00:03:36,897 --> 00:03:40,464 mit den Faktoren für Rabatt und Mehrwertsteuer ausmultipliziert 70 00:03:40,647 --> 00:03:43,497 und auf zwei Nachkommastellen gerundet ausgegeben. 71 00:03:44,747 --> 00:03:48,181 Wird der anonyme Block ausgeführt, kommt es zu einer Fehlermeldung: 72 00:03:48,864 --> 00:03:51,497 "ID Nettoverkaufspreis muss deklariert werden." 73 00:03:52,947 --> 00:03:55,380 Die Zeilen Nummer des Fehlers bezieht sich hier 74 00:03:55,380 --> 00:03:59,247 auf den Fundort des Fehlers ab Beginn der Anweisung oder Markierung. 75 00:04:00,597 --> 00:04:04,097 In der SQL-Abfrage gibt es den Nettoverkaufspreis allerdings 76 00:04:04,097 --> 00:04:07,830 nur als Attribut einer Relation, nicht als lokale Variable. 77 00:04:09,180 --> 00:04:12,530 Im Deklarationsabschnitt finden wir jedoch eine gleichnamige 78 00:04:12,530 --> 00:04:15,564 lokale Variable mit dem Präfix l_. 79 00:04:16,497 --> 00:04:19,547 Eine Deklaration der Variable hat also stattgefunden, 80 00:04:19,880 --> 00:04:22,647 nur wurde hier das Präfix l_ vergessen. 81 00:04:23,214 --> 00:04:24,530 Das trage ich nun nach. 82 00:04:28,013 --> 00:04:29,897 Ein erneutes Ausführen erzeugt 83 00:04:29,897 --> 00:04:33,330 nun eine weitere Fehlermeldung: "Keine Daten gefunden." 84 00:04:34,130 --> 00:04:36,230 Anhand der Zeilen Nummer ist erkennbar, 85 00:04:36,530 --> 00:04:39,563 dass es sich hier um einen SQL-Abfrage Fehler handelt 86 00:04:39,797 --> 00:04:42,480 und die Abfrage ein leeres Ergebnis zurückgibt. 87 00:04:43,463 --> 00:04:44,930 Ich korrigiere das, indem 88 00:04:44,930 --> 00:04:48,597 ich eine Artikelnummer eintrage, die in der Relation vorhanden ist. 89 00:04:49,430 --> 00:04:52,130 Jetzt wird der erwartete Verkaufspreis ausgegeben. 90 00:04:53,063 --> 00:04:54,930 Damit dieses Programm leicht von einer 91 00:04:54,930 --> 00:04:59,447 Anwendung aufgerufen werden kann, soll es als STORED FUNCTION in der 92 00:04:59,447 --> 00:05:02,096 Datenbank als Funktion Verkaufspreis gespeichert werden. 93 00:05:04,996 --> 00:05:08,480 Nun deklariere ich die Funktion zur Ermittlung des Verkaufspreises 94 00:05:08,480 --> 00:05:12,113 mit der Signatur CREATE OR REPLACE FUNCTION Verkaufspreis. 95 00:05:13,196 --> 00:05:16,546 Als Übergabe Parameter definiere ich die Artikelnummer 96 00:05:16,546 --> 00:05:20,930 mit in_artikelnummer IN NUMBER und den prozentualen 97 00:05:20,930 --> 00:05:24,113 Rabatt mit in_rabatt IN NUMBER. 98 00:05:25,280 --> 00:05:28,530 Den deklarativen Abschnitt übernehme ich aus dem zuvor 99 00:05:28,530 --> 00:05:32,213 erstellten anonymen Block und passe den Rabatt entsprechend an. 100 00:05:33,296 --> 00:05:34,646 Dabei fällt auf, dass 101 00:05:34,646 --> 00:05:36,596 die lokale Variable für den Nettoverkaufspreis 102 00:05:36,596 --> 00:05:39,596 mit einem Syntax Fehler markiert wird. 103 00:05:40,429 --> 00:05:44,179 Weil es keine genaueren Angaben zum Fehler gibt, fahre ich zunächst 104 00:05:44,179 --> 00:05:45,029 fort. 105 00:05:45,829 --> 00:05:50,096 Den Programmcode übernehme ich auch und führe die Funktion zum Test aus. 106 00:05:50,813 --> 00:05:53,513 Diesmal wird der Programmcode jedoch nicht wie der anonyme Block 107 00:05:53,513 --> 00:05:57,113 ausgeführt, sondern kompiliert und in der Datenbank gespeichert. 108 00:05:58,013 --> 00:06:00,713 Dabei werden wir auf den folgenden Fehler hingewiesen: 109 00:06:01,129 --> 00:06:04,313 "Fand das Symbol l_nettoverkaufspreis 110 00:06:04,313 --> 00:06:07,046 als eines der folgenden erwartet wurde: return." 111 00:06:08,062 --> 00:06:11,479 Die angezeigten Zeilen und Spalten Nummern des Fehlers beziehen 112 00:06:11,479 --> 00:06:15,862 sich jetzt im "Compiler-Log" auf das SQL-Skript und in der 113 00:06:15,862 --> 00:06:18,262 Skript Ausgabe auf den Code in der Datenbank. 114 00:06:19,762 --> 00:06:22,046 Wird keine Fehler Beschreibung angezeigt, 115 00:06:22,046 --> 00:06:24,779 kann diese mit SHOW ERRORS aufgerufen werden. 116 00:06:25,912 --> 00:06:28,546 Nach dem Aktualisieren und Öffnen der Funktionen- 117 00:06:28,546 --> 00:06:32,962 Rubrik im Datenbank-Explorer wird die Funktion Verkaufspreis 118 00:06:33,262 --> 00:06:36,979 mit einem weißen X in einem roten Kreis als Fehler markiert. 119 00:06:37,996 --> 00:06:39,179 Mit einem Klick auf 120 00:06:39,179 --> 00:06:43,162 die in der Datenbank gespeicherte Funktion wird der Inhalt angezeigt 121 00:06:43,162 --> 00:06:45,562 und kann bearbeitet werden. 122 00:06:45,562 --> 00:06:49,079 Im Normalfall wird die mit Zeile Spalte angegebene Fehler 123 00:06:49,079 --> 00:06:52,645 Position zusätzlich mit einer roten Markierung gekennzeichnet. 124 00:06:53,729 --> 00:06:57,379 Durch die Fehlermeldung ist nun klar, dass hier vor ein RETURN 125 00:06:57,379 --> 00:07:00,812 mit dem Typ des Funktions-Rückgabe- wertes eingefügt werden muss. 126 00:07:02,279 --> 00:07:04,762 Im SQL-Skript beseitige ich den Fehler, 127 00:07:05,112 --> 00:07:07,795 gebe RETURN NUMBER AS ein 128 00:07:07,945 --> 00:07:10,762 und kompiliere erneut. 129 00:07:11,662 --> 00:07:14,012 Nach dem Aktualisieren verschwindet die Fehler 130 00:07:14,012 --> 00:07:15,895 Markierung an der Funktion. 131 00:07:15,895 --> 00:07:19,312 Um sicherzugehen, dass die Funktion fehlerfrei ist, kann im 132 00:07:19,312 --> 00:07:22,645 Kontextmenü: "Für Debug kompilieren" angeklickt werden. 133 00:07:24,512 --> 00:07:27,078 Ein grüner Punkt auf dem Funktionsnamen zeigt 134 00:07:27,078 --> 00:07:30,112 nun an, dass es keine Compiler- Fehler mehr gibt. 135 00:07:31,228 --> 00:07:34,612 Der Fehler kann auch direkt in der Datenbank korrigiert werden 136 00:07:34,612 --> 00:07:37,462 und mit dem Zahnrad Symbol erneut kompiliert werden. 137 00:07:38,095 --> 00:07:38,612 Das birgt 138 00:07:38,612 --> 00:07:42,512 aber die Gefahr, dass die Korrektur im SQL-Skript vergessen wird 139 00:07:42,712 --> 00:07:46,345 und so später durch erneutes ausführen des Skripts verworfen wird. 140 00:07:48,511 --> 00:07:51,678 Zum Test der Funktion führe ich eine kurze Verkaufspreisabfrage 141 00:07:51,678 --> 00:07:55,861 in einem anonymen Block aus und erhalte erneut eine Fehlermeldung 142 00:07:57,061 --> 00:08:00,511 "PL/SQL: Funktion hat keinen Wert zurückgegeben." 143 00:08:01,128 --> 00:08:03,595 Es wird also kein Wert von der Funktion zurückgegeben. 144 00:08:04,078 --> 00:08:06,961 Dann sehe ich in der Datenbank gespeicherten Funktion nach 145 00:08:06,961 --> 00:08:10,078 und stelle fest, dass das abschließende RETURN fehlt, 146 00:08:10,078 --> 00:08:12,411 wo jetzt noch eine Ausgabe aufgerufen wird. 147 00:08:13,611 --> 00:08:16,561 Im SQL-Skript ergänze ich an der Stelle RETURN 148 00:08:16,561 --> 00:08:20,428 und reduziere die Textausgabe auf die Rückgabe einer Zahl, 149 00:08:20,628 --> 00:08:23,778 damit der Übergabe-Typ stimmt und kompilierte erneut. 150 00:08:31,078 --> 00:08:31,494 Der Test 151 00:08:31,494 --> 00:08:34,711 der Funktion gibt jetzt wie gewünscht den Verkaufspreis aus. 152 00:08:35,878 --> 00:08:38,578 Anstatt mit einem anonymen Block kann das 153 00:08:39,078 --> 00:08:42,261 Ergebnis nun auch mit einem SQL- Query ausgegeben werden. 154 00:08:46,978 --> 00:08:48,444 Der Verkauf eines Artikels 155 00:08:48,444 --> 00:08:50,728 wird nun mit einer Prozedur abgebildet, 156 00:08:50,961 --> 00:08:55,011 die als Parameter die Bezeichnung und Anzahl des verkauften Artikels 157 00:08:55,011 --> 00:08:57,361 sowie den gewährten Rabatt übergeben bekommt. 158 00:08:58,194 --> 00:09:01,227 Die Beleg Nummer wird von einer SEQUENCE eindeutig generiert. 159 00:09:02,061 --> 00:09:05,461 Die Artikelnummer wird anhand der Artikelbezeichnung aus der Artikel 160 00:09:05,461 --> 00:09:06,711 Tabelle geholt. 161 00:09:06,711 --> 00:09:11,061 Dabei wird das einelementige Ergebnis der Abfrage mit dem Schlüsselwort 162 00:09:11,061 --> 00:09:14,511 INTO in die Variable l_artikelnummer gespeichert. 163 00:09:15,744 --> 00:09:17,727 Um den Verkauf zu dokumentieren, 164 00:09:17,727 --> 00:09:20,394 wird in der Tabelle Verkäufe persistiert. 165 00:09:21,377 --> 00:09:23,911 Dazu verwende ich die generierte Belegnummer, 166 00:09:24,111 --> 00:09:26,927 die ermittelte Artikelnummer, die übergebene Anzahl 167 00:09:27,210 --> 00:09:30,627 und den durch die Funktion errechneten Verkaufspreis pro Stück, 168 00:09:31,044 --> 00:09:33,260 der noch mit der Anzahl multipliziert wird, 169 00:09:33,260 --> 00:09:35,477 um die Endsumme des Einkaufs zu erhalten. 170 00:09:37,160 --> 00:09:39,927 Ist diese Prozedur nun kompiliert, können einzelne 171 00:09:39,927 --> 00:09:41,777 Artikel verkauft werden. 172 00:09:41,777 --> 00:09:45,810 Dazu führe ich für jeden verkauften Artikel die Prozedur verkaufen aus 173 00:09:46,077 --> 00:09:47,127 und übergebe ihr 174 00:09:47,127 --> 00:09:50,394 die Artikelbeschreibung, die Anzahl und den gewährten Rabatt. 175 00:09:51,294 --> 00:09:54,210 Um Verkäufe noch mit einem ROLLBACK stornieren zu können, 176 00:09:54,477 --> 00:09:56,727 beende ich den Einkauf mit einem COMMIT. 177 00:09:57,827 --> 00:09:58,344 Zum Schluss 178 00:09:58,344 --> 00:10:01,377 noch einen Blick auf die in der Datenbank abgelegten Verkäufe. 179 00:10:02,277 --> 00:10:05,577 Dazu verwende ich eine Abfrage, in der die Relationen 180 00:10:05,577 --> 00:10:09,110 Artikel und Verkäufe mit einem Natural Join verknüpft werden 181 00:10:09,327 --> 00:10:12,110 und die erfassten Daten formatiert ausgegeben werden. 182 00:10:13,260 --> 00:10:15,927 So sehen wir eine schöne Auflistung aller verkauften 183 00:10:15,927 --> 00:10:18,560 Möbel mit dem erzielten Verkaufsergebnis. 184 00:10:19,910 --> 00:10:21,143 Vielen Dank für's Zusehen. 185 00:10:21,143 --> 00:10:22,077 Bis zum nächsten Mal.