/* ************************************************************************ PL/SQL mit dem SQL-Developer entwickeln – Wie der Einstieg und die Fehlersuche gelingt Autor: Jens Lambert, Hochschule Düsseldorf Version: 3, im Juli 2022 Lizenz: CC BY-SA 4.0 Lizenzbedingungen: https://creativecommons.org/licenses/by-sa/4.0/deed.de Der SQL-Developer unterliegt den Lizenzbedingungen der Oracle Corporation https://www.oracle.com, Stand Juli 2022. ************************************************************************ */ -- Der Möbelkatalog -- Eingaben auch in Skriptausgabe anzeigen SET ECHO ON -- PL/SQL Server Meldungen in Skriptausgabe anzeigen SET SERVEROUTPUT ON -- SQL Formatierung, optional SET LINESIZE 95 SET PAGESIZE 50000 SET SQLFORMAT ANSICONSOLE -- Alte Tabellen entfernen DROP FUNCTION verkaufspreis; DROP PROCEDURE verkaufen; DROP TABLE verkaeufe; DROP SEQUENCE belegnummer_seq; DROP TABLE artikel; -- ######################################################################## -- PL/SQL ausführen EXECUTE dbms_output.put_line('Hallo Welt!'); -- PL/SQL Server Meldungen in Skriptausgabe anzeigen SET SERVEROUTPUT ON BEGIN dbms_output.put('Hallo'); dbms_output.put(' Welt'); dbms_output.put_line('!'); dbms_output.put_line('-----------'); END; -- ######################################################################## -- Tabellen für das Möbelkaufhaus vorbereiten -- Die Artikel werden in einem Katalog gespeichert CREATE TABLE artikel ( artikelnummer NUMBER(8) CONSTRAINT artikel_pk PRIMARY KEY, bezeichnung VARCHAR2(25) NOT NULL, nettoeinkaufspreis NUMBER(8,2) NOT NULL, nettoverkaufspreis NUMBER(8,2) NOT NULL ); -- Es darf nicht unter Einkaufspreis verkauft werden. ALTER TABLE artikel ADD CONSTRAINT artikel_nettoverkaufspreis_ck CHECK (nettoverkaufspreis > nettoeinkaufspreis); -- Der Artikel Katalog wird gefüllt INSERT INTO artikel VALUES(1, 'Sofa - William', 420.00, 835.45); INSERT INTO artikel VALUES(2, 'Sessel - Mia', 140.00, 275.45); INSERT INTO artikel VALUES(3, 'Tisch - Isabella', 210.00, 415.45); INSERT INTO artikel VALUES(4, 'Stuhl - Lucas', 65.00, 125.45); INSERT INTO artikel VALUES(5, 'Bett - Finn', 310.00, 615.45); INSERT INTO artikel VALUES(6, 'Design Liege - James', 460.00, 1200.45); COMMIT; -- Ausgabe aller gespeicherten Artikel SELECT * FROM artikel; -- Automatische Erzeugung von eindeutigen Belegnummern für Verkäufe CREATE SEQUENCE belegnummer_seq START WITH 1001 INCREMENT BY 1; -- Jeder Verkauf wird dokumentiert CREATE TABLE verkaeufe ( belegnummer NUMBER(8) CONSTRAINT verkaeufe_pk PRIMARY KEY, artikelnummer NUMBER(8) CONSTRAINT verkaeufe_artikel_fk REFERENCES artikel (artikelnummer), anzahl NUMBER(8) NOT NULL, verkaufspreis NUMBER(8,2) NOT NULL ); -- ######################################################################## -- anonymer Block MIT FEHLERN -- Ziel: Ausgabe des Verkaufspreises: DECLARE l_nettoverkaufspreis NUMBER(8,2):= 0; l_rabatt NUMBER(8,2) := ((100 - 10)/100); -- hier: -10% co_mwst CONSTANT NUMBER(8,2) := 1.19; BEGIN -- Verkaufspreis netto aus Artikel-Tabelle lesen SELECT nettoverkaufspreis INTO nettoverkaufspreis FROM artikel WHERE artikel.artikelnummer = 100; -- berechnen als Produkt aus Preis, Anzahl und MwSt. dbms_output.put_line('Verkaufspreis: '|| ROUND(l_nettoverkaufspreis * l_rabatt * co_mwst, 2) ||' €'); END; -- Fehler: -- 1) falscher Variablen-Bezeichner INTO -> l_nettoverkaufspreis -- 2) WHERE falsche Aritkelnummer -> 1 -- Fehler korrigiert: DECLARE l_nettoverkaufspreis NUMBER(8,2):= 0; l_rabatt NUMBER(8,2) := ((100 - 10)/100); -- hier: -10% co_mwst CONSTANT NUMBER(8,2) := 1.19; BEGIN -- Verkaufspreis netto aus Artikel-Tabelle lesen SELECT nettoverkaufspreis INTO l_nettoverkaufspreis FROM artikel WHERE artikel.artikelnummer = 1; -- berechnen als Produkt aus Preis, Anzahl und MwSt. dbms_output.put_line('Verkaufspreis: '|| ROUND(l_nettoverkaufspreis * l_rabatt * co_mwst, 2) ); END; -- ######################################################################## -- FUNKTION MIT FEHLERN /** Berechnung des Verkaufspreises @param in_artikelnummer Artikelnummer des verkauften Artikels @param in_rabatt Rabatt des verkauften Artikels (0-100%) @return aktueller Verkaufspreis des Artikels mit MwSt. und Rabatt */ CREATE OR REPLACE FUNCTION verkaufspreis(in_artikelnummer IN NUMBER, in_rabatt IN NUMBER) l_nettoverkaufspreis NUMBER(8,2):= 0; l_rabatt NUMBER(8,2) := ((100 - in_rabatt)/100); co_mwst CONSTANT NUMBER(8,2) := 1.19; BEGIN -- Verkaufspreis netto aus Artikel-Tabelle lesen SELECT nettoverkaufspreis INTO l_nettoverkaufspreis FROM artikel WHERE artikel.artikelnummer = in_artikelnummer; -- berechnen als Produkt aus Preis, Anzahl und MwSt. dbms_output.put_line('Verkaufspreis: '|| ROUND(l_nettoverkaufspreis * l_rabatt * co_mwst, 2) ); -- EXCEPTION -- hier können Ausnahmen behandelt werden END verkaufspreis; -- SHOW ERRORS -- Fehler: -- 1) Rückgabewert mit richtigem Datentyp fehlt: -- Für Debug kompilieren, Zeile ansehen, im Skript korrigieren, erneut kompilieren -- 2) Ausgabe zu RETURN abändern. -- ######################################################################## -- Fehler korrigiert: /** Berechnung des Verkaufspreises @param in_artikelnummer Artikelnummer des verkauften Artikels @param in_rabatt Rabatt des verkauften Artikels (0-100%) @return aktueller Verkaufspreis des Artikels mit MwSt. und Rabatt */ CREATE OR REPLACE FUNCTION verkaufspreis(in_artikelnummer IN NUMBER, in_rabatt IN NUMBER) RETURN NUMBER AS l_nettoverkaufspreis NUMBER(8,2):= 0; l_rabatt NUMBER(8,2) := (100 - in_rabatt)/100; co_mwst CONSTANT NUMBER(8,2) := 1.19; BEGIN -- Verkaufspreis netto aus Artikel-Tabelle lesen SELECT nettoverkaufspreis INTO l_nettoverkaufspreis FROM artikel WHERE artikel.artikelnummer = in_artikelnummer; -- berechnen als Produkt aus Preis, Anzahl und MwSt. RETURN ROUND(l_nettoverkaufspreis * l_rabatt * co_mwst , 2); -- EXCEPTION -- hier können Ausnahmen behandelt werden END verkaufspreis; -- ######################################################################## -- Test der Funktion mit anonymen Block BEGIN DBMS_OUTPUT.PUT_LINE('Verkauft für: '|| verkaufspreis(1,10)||' € inkl. 19% MwSt.'); END; -- Test der Funktion als Query SELECT verkaufspreis(1,10)||' € inkl. 19% MwSt.' AS "Verkauft für" FROM DUAL; -- ######################################################################## /** Prozedur zum persistieren von Verkäufen. @param in_bezeichnung Bezeichnung des verkauften Artikels @param in_anzahl Anzahl des verkauften Artikels */ CREATE OR REPLACE PROCEDURE verkaufen(in_bezeichnung IN VARCHAR2, in_anzahl IN NUMBER, in_rabatt IN NUMBER) AS l_belegnummer NUMBER(8) := belegnummer_seq.nextval; l_artikelnummer NUMBER; BEGIN SELECT artikelnummer INTO l_artikelnummer FROM artikel WHERE bezeichnung = in_bezeichnung; -- Verkauf in der Relation eintragen INSERT INTO verkaeufe VALUES (l_belegnummer, l_artikelnummer, in_anzahl, verkaufspreis(l_artikelnummer, in_rabatt) * in_anzahl); -- EXCEPTION -- hier können Ausnahmen behandelt werden END verkaufen; -- Nun wird etwas verkauft.... EXECUTE verkaufen('Bett - Finn', 1,0); EXECUTE verkaufen('Sessel - Mia', 2,0); EXECUTE verkaufen('Sofa - William', 1,0); EXECUTE verkaufen('Tisch - Isabella', 1,0); EXECUTE verkaufen('Stuhl - Lucas', 4,10); COMMIT; SELECT belegnummer AS "Beleg", artikelnummer AS "Art. Nr.", bezeichnung AS "Bezeichnung", TO_CHAR(nettoeinkaufspreis,'L99G999D99MI') AS "Einkauf", TO_CHAR(nettoverkaufspreis,'L99G999D99MI') AS "Verkauf", anzahl AS "Anzahl", TO_CHAR(verkaufspreis, 'L99G999D99MI') AS "Verkauf Summe" FROM artikel NATURAL JOIN verkaeufe ORDER BY belegnummer;