(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Minimalbeispiel
BEGIN
FOR rec IN (SELECT ghi.id FROM geraetehistorien ghi WHERE ghi.id < 500) LOOP
dbms_output.put_line(rec.id);
pkg_ghi.prc_del_ghi_eintrag(p_ghi_id => rec.id);
END LOOP;
END;
/
Sauberes Arbeiten mit Testmodus und Protokollierung
-- 2. Sauber arbeiten mit Testmodus und Protokollierung
DECLARE
l_test CONSTANT BOOLEAN := TRUE; -- TODO: Testmodus
l_err VARCHAR2(1000) := NULL;
l_commit BOOLEAN := TRUE; -- wird bei Problemen mit false überschrieben, nie mit true befüllt
l_output VARCHAR2(1000);
l_count NUMBER := 0;
l_count_good NUMBER := 0;
l_count_error NUMBER := 0;
BEGIN
-- dbms_output.enable; -- verhindert Pufferüberlauf wenn als Procedure gestartet.
--
-- Eine Beispielschleife
--
l_output := 'Nr' || ' ; ' || 'ID';
dbms_output.put_line(l_output);
FOR rec IN (SELECT ghi.id FROM geraetehistorien ghi WHERE ghi.id < 500) LOOP
BEGIN
-- neuer BEGIN-Block um hier gesondert Exceptions zu fangen
l_err := NULL; -- Viele Prozeduren geben Fehlermeldungen zurück, mit diesen ist dann l_err zu füllen
l_count := l_count + 1;
--
-- Hauptteil z.B.: erst Ausgabe, dann GHI Löschen
--
l_output := l_count || ' ; ' || rec.id; -- hier eine Ausgabevariable für DBMS Put Line und Protokoll setzen
dbms_output.put_line(l_output);
--
-- Ende Hauptteil
--
--
-- Fehlerbehandlung etc
--
IF l_err IS NOT NULL THEN
l_commit := FALSE;
l_count_error := l_count_error + 1;
ELSE
l_count_good := l_count_good + 1;
END IF;
EXCEPTION
WHEN OTHERS THEN
l_commit := FALSE;
l_count_error := l_count_error + 1;
l_output := 'ERROR: ' || SQLERRM;
dbms_output.put_line(l_output);
END; -- block innerhalb for schleife
END LOOP;
-- commit erst am Ende, und nur wenn keine Fehler und kein Testmodus
IF l_commit = TRUE THEN
l_output := 'No Errors';
dbms_output.put_line(l_output);
IF l_test THEN
l_output := 'TEST -> ROLLBACK of all statements';
dbms_output.put_line(l_output);
ROLLBACK;
ELSE
l_output := 'COMMIT';
dbms_output.put_line(l_output);
COMMIT;
END IF;
ELSE
-- l_commit ist nicht gesetzt, weil Fehler
l_output := 'ERRORS -> ROLLBACK';
dbms_output.put_line(l_output);
ROLLBACK;
END IF;
--
-- Zusammenfassung
--
dbms_output.put_line(l_lpl_id, '-- ');
dbms_output.put_line(l_lpl_id, '-- Zusammenfassung');
dbms_output.put_line(l_lpl_id, '-- bearbeitet: ' || l_count);
dbms_output.put_line(l_lpl_id, '-- gut : ' || l_count_good);
dbms_output.put_line(l_lpl_id, '-- fehlerhaft: ' || l_count_error);
dbms_output.put_line(l_lpl_id, '-- ');
--
-- Exeptions
--
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR: ' || SQLCODE || ' - ' || SQLERRM);
ROLLBACK;
END;
/
Ausgabe
-- SET SERVEROUTPUT ON -- dbms output aktivieren im SQL-Developer (PL/SQL-Dev macht das automatisch)
DECLARE
ln_num NUMBER;
lv_text VARCHAR2(32);
BEGIN
ln_num := 12345;
lv_text := 'qwertz';
dbms_output.put_line('ln_num = ' || ln_num || ', lv_text = ' || lv_text);
END;
/
Variablen
/*
Variablennamenskonvention
1. Stelle: Lokale vs. Übergabevariable
- Lokale (deklarierte) Variablen mit ‚l‘ beginnend
- Prozedur-Übergabe Variablen mit ‚p‘ beginnend
2. Stelle: Typ
- n für Number
- V für Varchar2 (String/Zeichenkette)
- B für Boolean (true/false)
3… Stelle: ‚_Bezeichnung‘
*/
-- Minimalbeispiel
DECLARE -- kann weggelassen werden wenn nichts zu deklarieren
ln_num NUMBER := 0;
ln_num2 CONSTANT NUMBER := 123;
BEGIN
ln_num := 12345;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR: ' || SQLCODE || ' - ' || SQLERRM);
END;
/
/*
Zwischen BEGIN und END können weitere gekapselte
DECLARE
BEGIN
EXCEPTION
END
-Blöcke eingefügt werden, Beispiel siehe Schleife mit Exception-Behandlung
*/
-- Variablen 1
DECLARE
ln_num number;
lv_text VARCHAR2(32);
BEGIN
ln_num := 12345;
dbms_output.put_line('num = ' || ln_num);
lv_text := 'qwertz';
dbms_output.put_line('text = ' || lv_text);
END;
/
-- Variablen 2 - Via SQL befüllen
DECLARE
ln_lpl_id lineare_protokolle.id%type; -- %TYPE liest den Variablentyp aus der Tabellenspalte aus -> SEHR praktisch!
lv_lpl_titel lineare_protokolle.beschreibung%TYPE;
BEGIN
SELECT t.id, t.beschreibung
INTO ln_lpl_id, lv_lpl_titel
FROM lineare_protokolle t
WHERE t.id = (SELECT MAX(id) FROM lineare_protokolle);
dbms_output.put_line('ID = ' || ln_lpl_id || ', Titel = ' || lv_lpl_titel);
END;
/
-- Variablen 3 - Insert in DB
DECLARE
ln_num lineare_protokolle.id%TYPE;
lv_lpl_titel lineare_protokolle.beschreibung%TYPE;
BEGIN
ln_num := 12345;
lv_lpl_titel := 'asdfg';
insert into lineare_protokolle(id,beschreibung) values (ln_num,lv_lpl_titel);
END;
/
-- Variablen 4 - Update in DB
DECLARE
ln_num tabelle.spalte1%TYPE := 0;
BEGIN
UPDATE tabelle
SET (spalte1) = (ln_num)
WHERE spalte2 = 123; --filter
END;
/
-- Löschen mit RowCount
declare
ln_num tab.spalte1%TYPE := 0;
ln_num_del number;
BEGIN
DELETE FROM employees WHERE employee_id = ln_num;
ln_num_del := SQL%ROWCOUNT;
DBMS_OUTPUT.PUT_LINE(ln_num_del || ' rows deleted.');
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' rows deleted.');
END;
Schleifen
-- Prozedur ausführen
BEGIN
pkg_ghi.prc_del_ghi_eintrag(p_ghi_id => 123123123);
END;
/
-- Besser Exceptions fangen und ausgeben
BEGIN
pkg_ghi.prc_del_ghi_eintrag(p_ghi_id => 123123123);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR: ' || SQLCODE || ' - ' || SQLERRM);
END;
/
-- For-Schleife - Minimalbeispiel
BEGIN
FOR rec IN (SELECT * FROM geraetehistorien ghi WHERE ghi.id < 500) LOOP
dbms_output.put_line(rec.id);
-- pkg_ghi.prc_del_ghi_eintrag(p_ghi_id => rec.id);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR: ' || SQLCODE || ' - ' || SQLERRM);
END;
/
-- For-Schleife mit If-Else
BEGIN
FOR rec IN (SELECT ghi.id FROM geraetehistorien ghi WHERE ghi.id < 500) LOOP
IF (rec.id > 500) THEN
dbms_output.put_line('lösche GHI-ID ' || rec.id);
-- pkg_ghi.prc_del_ghi_eintrag(p_ghi_id => rec.id);
ELSE
dbms_output.put_line('lösche GHI-ID ' || rec.id || ' nicht');
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR: ' || SQLCODE || ' - ' || SQLERRM);
END;
/
-- For-Schleife mit EXCEPTION-Behandlung im Loop (Macht nach Fehler weiter)
BEGIN
FOR rec IN (SELECT ghi.id FROM geraetehistorien ghi WHERE ghi.id < 500) LOOP
BEGIN
-- separater Beginn Block, für Exceptions
-- pkg_ghi.prc_del_ghi_eintrag(p_ghi_id => rec.id);
dbms_output.put_line('lösche GHI-ID ' || rec.id);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR: ' || SQLCODE || ' - ' || SQLERRM);
END; -- innerer Begin Block
END LOOP;
END;
/
-- Schleife über Liste von Werten
-- http://www.knaupes.net/oracle-plsql-for-schleife/
DECLARE
TYPE person IS RECORD(
LAST_NAME VARCHAR2(16),
AGE NUMBER);
TYPE personTab IS TABLE OF person;
vPersons personTab := personTab();
BEGIN
-- befüllen der Tabelle
vPersons.extend;
vPersons(1).LAST_NAME := 'KING';
vPersons(1).AGE := '32';
vPersons.extend;
vPersons(2).LAST_NAME := 'QUEEN';
vPersons(2).AGE := '31';
FOR i IN vPersons.first .. vPersons.last LOOP
dbms_output.put_line(vPersons(i).LAST_NAME || ' - ' || vPersons(i).AGE);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR: ' || SQLCODE || ' - ' || SQLERRM);
END;
Prozeduren
--erstellen und in DB speichern
CREATE OR REPLACE PROCEDURE myproc(pn_card_id NUMBER, pv_loc varchar2) is
ln_counter number;
BEGIN
ln_counter := ln_counter + 1;
INSERT INTO tab1 VALUES (pn_card_id, pv_loc);
end myproc;
/
--ausführen
begin
myproc(pn_card_id => 123, pv_loc => 'test');
end;
/
--löschen
drop PROCEDURE myproc;
-- Procedure in Anonymen Block verwenden
DECLARE
lv_text VARCHAR2(16) := 'asdfg';
PROCEDURE myproc(pn_card_id NUMBER, pv_loc NUMBER) IS
ln_counter NUMBER := 0;
BEGIN
ln_counter := ln_counter + 1;
INSERT INTO tab1 VALUES (pn_card_id, pv_loc);
END myproc;
BEGIN
myproc(123, lv_text);
END;
/
-- Exception Rückgabe aus Prozedur raus
CREATE OR REPLACE PROCEDURE myproc (pn_card_id IN NUMBER, pv_loc IN NUMBER, pv_error OUT varchar2) is
ln_counter number := 0;
BEGIN
pv_error := null;
ln_counter := ln_counter + 1;
INSERT INTO tab1 VALUES (pn_card_id, pv_loc);
EXCEPTION
WHEN OTHERS THEN
pv_error := 'ERROR: ' || SQLCODE || ' - ' || SQLERRM;
end myproc;
/
Performance Tipps
-- fastest: plain SQL
INSERT all
INTO tab1 (owner, table_name) VALUES ('EC_ANF', 'ANFRAGEN')
INTO tab1 (owner, table_name) VALUES ('EC_ANF', 'ANFRAGE_PARAMETER')
INTO tab1 (owner, table_name) VALUES ('EC_ANF', 'ANFRAGEVERMERKE')
INTO tab1 (owner, table_name) VALUES ('EC_ANF', 'KUNDEN')
SELECT 1 FROM DUAL; -- select muss hier sein
-- slow: Context switches SQL to PL/SQL
FOR I IN 1..5600 LOOP
SELECT product_id, warehouse_id
INTO vn_p_id, vn_wh_id
FROM big_inventories WHERE v_p_id = I;
INSERT INTO inventories2 VALUES(vn_p_id, vn_wh_id);
END LOOP
-- better: via Cursor
DECLARE
CURSOR cv_raise IS
SELECT deptno, increase FROM emp_raise;
BEGIN
FOR dept IN cv_raise LOOP
UPDATE big_emp SET sal = sal * dept.increase WHERE deptno = dept.deptno;
END LOOP;
-- Bulk Collect
CREATE PROCEDURE get_departments(p_loc NUMBER) IS
TYPE dept_tab_type IS TABLE OF departments%ROWTYPE;
v_depts dept_tab_type;
BEGIN
SELECT * BULK COLLECT INTO v_depts FROM departments WHERE location_id = p_loc;
FOR i IN 1 .. v_depts.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(v_depts(i).department_id || ' ' || v_depts(i).department_name);
END LOOP;
END;
-- Bulk Binding
FORALL i IN v_id.FIRST .. v_id.LAST
UPDATE employees
SET salary = (1 + p_percent / 100) * salary
WHERE employee_id = v_id(i);
END;