prog:plsql_code_pices
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende Überarbeitung | |||
prog:plsql_code_pices [2019/02/12 11:14] – [PL/SQL - Code Beispiele] gpipperr | prog:plsql_code_pices [2019/02/12 11:14] (aktuell) – [Mit langen Strings arbeiten] gpipperr | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
+ | ===== PL/SQL - Code Beispiele ===== | ||
+ | |||
+ | PL/SQL Code Beispiele - Was immer wieder täglich gebraucht wird. | ||
+ | |||
+ | |||
+ | === Mit langen Strings arbeiten === | ||
+ | |||
+ | |||
+ | Mit dem q' | ||
+ | |||
+ | |||
+ | <code plsql> | ||
+ | |||
+ | v_my_very_long_string := q' | ||
+ | |||
+ | select **** from xxxx where yyy in (' | ||
+ | ]'; | ||
+ | |||
+ | </ | ||
+ | ==== Collections ==== | ||
+ | |||
+ | === PL/SQL Table definieren=== | ||
+ | |||
+ | ==Associative Arrays (vor Oracle 10g " | ||
+ | |||
+ | Typ definieren: | ||
+ | <code plsql> | ||
+ | TYPE myPlsqltab is TABLE OF varchar2(2000) index by binary_integer; | ||
+ | </ | ||
+ | |||
+ | Variable deklarieren: | ||
+ | <code plsql> | ||
+ | v_texte myPlsqltab; | ||
+ | </ | ||
+ | |||
+ | Werte zuweisen: | ||
+ | <code plsql> | ||
+ | v_texte(3): | ||
+ | v_texte(4): | ||
+ | v_texte(8): | ||
+ | |||
+ | </ | ||
+ | |||
+ | Anzahl der Elemente mit count | ||
+ | < | ||
+ | dbms_output.put_line(' | ||
+ | </ | ||
+ | |||
+ | Wert in einer Schleife auslesen: | ||
+ | <code plsql> | ||
+ | |||
+ | -- loop over the table | ||
+ | for i in v_texte.first .. v_texte.last | ||
+ | loop | ||
+ | -- ausgeben | ||
+ | if v_texte.exists(i) | ||
+ | then | ||
+ | dbms_output.put_line(' | ||
+ | end if; | ||
+ | end loop; | ||
+ | | ||
+ | -- loop over gaps | ||
+ | v_count := v_texte.first; | ||
+ | while v_count is not null | ||
+ | loop | ||
+ | | ||
+ | | ||
+ | end loop; | ||
+ | |||
+ | </ | ||
+ | |||
+ | Komplettes Beispiel: {{: | ||
+ | |||
+ | Ein " | ||
+ | |||
+ | Beispiel um einen Lookup bei einem ETL Job für jeden Datensatz die Abfrage zu vermeiden, die ID's können 16 stellen enthalten: | ||
+ | <code sql> | ||
+ | declare | ||
+ | type t_emp_lookup_tab is table of emp_lookup.id%type INDEX BY varchar2(16); | ||
+ | |||
+ | v_emp_lookuptab | ||
+ | |||
+ | cursor c_emp_lookup | ||
+ | is | ||
+ | select id | ||
+ | , max (deptno) as deptno | ||
+ | from emp_deptno_lookup | ||
+ | group by id | ||
+ | order by id; | ||
+ | begin | ||
+ | for rec in c_emp_lookup | ||
+ | loop | ||
+ | v_emp_lookuptab (rec.id) := rec.deptno; | ||
+ | end loop; | ||
+ | dbms_output.put_line ('Fond for Smith wie the pers id 14857470850200 = ::' || v_emp_lookuptab (14857470850200)); | ||
+ | end; | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | siehe auch http:// | ||
+ | |||
+ | ==Nested Tables== | ||
+ | |||
+ | Unterschied => auf "index by" wird verzichtet! | ||
+ | |||
+ | Typ definieren: | ||
+ | <code plsql> | ||
+ | TYPE varchar_t is TABLE OF varchar2(2000); | ||
+ | </ | ||
+ | |||
+ | |||
+ | Vergleich Nested Tables Collection in PL/SQL mit dem von dem **MULTISET UNION|INTERSECT|EXCEPT** Operatoren | ||
+ | |||
+ | <code plsql> | ||
+ | declare | ||
+ | |||
+ | TYPE varchar2_t IS TABLE OF VARCHAR2(2000); | ||
+ | |||
+ | v_name_a | ||
+ | v_name_b | ||
+ | v_name_diff varchar2_t; | ||
+ | v_all | ||
+ | v_sort | ||
+ | v_idx | ||
+ | |||
+ | begin | ||
+ | v_name_a: | ||
+ | v_name_b: | ||
+ | -- Gesamtmenge inkl. dubletten | ||
+ | v_name_diff := v_name_a MULTISET UNION v_name_b; | ||
+ | dbms_output.put_line(v_name_diff.count); | ||
+ | -- 6 A A B C D E | ||
+ | -- Schnittmenge, | ||
+ | v_name_diff := v_name_a MULTISET INTERSECT v_name_b; | ||
+ | dbms_output.put_line(v_name_diff.count); | ||
+ | --1 - A | ||
+ | -- Differenz | ||
+ | v_name_diff := v_name_a MULTISET EXCEPT | ||
+ | dbms_output.put_line(v_name_diff.count); | ||
+ | --2 - D E | ||
+ | |||
+ | --------- | ||
+ | -- reduce the multiset again to a list with no duplicates | ||
+ | v_all := SET(v_name_a MULTISET UNION v_name_b); | ||
+ | dbms_output.put_line(v_all.count); | ||
+ | -- 5 | ||
+ | | ||
+ | -- loop | ||
+ | v_idx := v_all.FIRST; | ||
+ | |||
+ | WHILE (v_idx IS NOT NULL) | ||
+ | LOOP | ||
+ | DBMS_OUTPUT.PUT_LINE | ||
+ | v_idx := v_all.NEXT(v_idx); | ||
+ | END LOOP; | ||
+ | end; | ||
+ | |||
+ | </ | ||
+ | |||
+ | Siehe => https:// | ||
+ | |||
+ | |||
+ | Sortieren mit Hilfe von SQL, dazu muss allerdings der Type als DB Object angelegt werden: | ||
+ | |||
+ | <code plsql> | ||
+ | CREATE TYPE varchar2_t IS TABLE OF varchar2(2000); | ||
+ | / | ||
+ | |||
+ | DECLARE | ||
+ | v_unsort | ||
+ | v_sort | ||
+ | v_idx | ||
+ | | ||
+ | BEGIN | ||
+ | v_unsort: | ||
+ | |||
+ | ----- | ||
+ | |||
+ | FOR rec IN (SELECT column_value val FROM TABLE(v_unsort) | ||
+ | LOOP | ||
+ | DBMS_OUTPUT.put_line(rec.val); | ||
+ | END LOOP; | ||
+ | | ||
+ | ------- | ||
+ | DBMS_OUTPUT.put_line(' | ||
+ | ----- | ||
+ | |||
+ | | ||
+ | | ||
+ | v_idx := v_sort.FIRST; | ||
+ | WHILE (v_idx IS NOT NULL) | ||
+ | LOOP | ||
+ | | ||
+ | v_idx := v_sort.NEXT(v_idx); | ||
+ | END LOOP; | ||
+ | | ||
+ | END; | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ==== Kontroll Strukturen==== | ||
+ | |||
+ | === Case Construkt === | ||
+ | |||
+ | Mit dem Case Construkt kann viel Tip Arbeit erspart werden: | ||
+ | |||
+ | <code plsql> | ||
+ | |||
+ | << | ||
+ | case v_gehalt | ||
+ | when 1000 then v_texte(1): | ||
+ | when 2000 then v_texte(1): | ||
+ | when 3000 then v_texte(1): | ||
+ | else v_texte(1): | ||
+ | end case Mein_CASE; | ||
+ | |||
+ | </ | ||
+ | |||
+ | Siehe auch [[prog: | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ==== Exception ==== | ||
+ | |||
+ | Mit " DBMS_OUTPUT.put_line(' | ||
+ | |||
+ | |||
+ | Eine eigene Exception definieren und aufrufen: | ||
+ | <code plsql> | ||
+ | set serveroutput on | ||
+ | declare | ||
+ | | ||
+ | | ||
+ | | ||
+ | begin | ||
+ | if v_value > 10 then | ||
+ | raise_application_error( -20020, 'Value to small:: ' || v_value); | ||
+ | else | ||
+ | raise wrong_value; | ||
+ | end if; | ||
+ | exception | ||
+ | when wrong_value then | ||
+ | DBMS_OUTPUT.put_line(' | ||
+ | DBMS_OUTPUT.put_line(' | ||
+ | when OTHERS then | ||
+ | DBMS_OUTPUT.put_line(' | ||
+ | end; | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | Benannte Exceptions abfangen: | ||
+ | |||
+ | <code sql> | ||
+ | |||
+ | create or replace function getuser(p_name varchar2) | ||
+ | return varchar2 | ||
+ | as | ||
+ | | ||
+ | begin | ||
+ | | ||
+ | | ||
+ | exception | ||
+ | when TOO_MANY_ROWS then | ||
+ | dbms_output.put_line(' | ||
+ | | ||
+ | dbms_output.put_line(' | ||
+ | when OTHERS then | ||
+ | dbms_output.put_line(' | ||
+ | end; | ||
+ | / | ||
+ | </ | ||
+ | Die wichtigen benannten Exceptions: | ||
+ | |||
+ | * CURSOR_ALREADY_OPEN | ||
+ | * DUP_VAL_ON_INDEX | ||
+ | * INVALID_CURSOR | ||
+ | * INVALID_NUMBER | ||
+ | * LOGIN_DENIED | ||
+ | * NO_DATA_FOUND | ||
+ | * NOT_LOGGED_ON | ||
+ | * PROGRAM_ERROR | ||
+ | * ROWTYPE_MISMATCH | ||
+ | * STORAGE_ERROR | ||
+ | * TIMEOUT_ON_RESOURCE | ||
+ | * TOO_MANY_ROWS | ||
+ | * VALUE_ERROR | ||
+ | * ZERO_DIVIDE | ||
+ | |||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ===== SQL Abfragen ===== | ||
+ | |||
+ | ==== Einfaches Open ==== | ||
+ | |||
+ | Die einfachste Variante einer Schleife über das Ergebniss einer SQL Abfrage: | ||
+ | <code plsql> | ||
+ | set serveroutput on | ||
+ | declare | ||
+ | cursor c_emp is select * from emp; | ||
+ | v_emp_rec c_emp%rowtype; | ||
+ | begin | ||
+ | open c_emp; | ||
+ | loop | ||
+ | fetch c_emp into v_emp_rec; | ||
+ | exit when c_emp%notfound; | ||
+ | DBMS_OUTPUT.put_line(' | ||
+ | end loop; | ||
+ | | ||
+ | DBMS_OUTPUT.put_line(' | ||
+ | | ||
+ | if c_emp%isopen | ||
+ | then | ||
+ | close c_emp; | ||
+ | end if; | ||
+ | | ||
+ | end; | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | ==== For Loop ==== | ||
+ | |||
+ | Mit for und einem impliziten Ergebniss Record läßt sich das ganze sehr kompakt schreiben: | ||
+ | <code plsql> | ||
+ | set serveroutput on | ||
+ | declare | ||
+ | cursor c_emp is select * from emp; | ||
+ | begin | ||
+ | for rec in c_emp | ||
+ | loop | ||
+ | DBMS_OUTPUT.put_line(' | ||
+ | end loop; | ||
+ | end; | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== Dynamisches SQL mit dem Ref Cursor ==== | ||
+ | |||
+ | Mit einem String ein SQL Statment definieren: | ||
+ | <code plsql> | ||
+ | |||
+ | declare | ||
+ | -- Weak Cursor | ||
+ | type rc_c1 is ref cursor; | ||
+ | -- cursor variable | ||
+ | | ||
+ | -- result type | ||
+ | | ||
+ | -- dynamic sql Text statments .-) | ||
+ | | ||
+ | begin | ||
+ | -- open Cursor for the text definition of the sql | ||
+ | open c_c1 for v_sql; | ||
+ | -- query | ||
+ | loop | ||
+ | fetch c_c1 into r_emp; | ||
+ | exit when c_c1%NOTFOUND; | ||
+ | | ||
+ | end loop; | ||
+ | | ||
+ | close c_c1; | ||
+ | end; | ||
+ | / | ||
+ | |||
+ | </ | ||
+ | |||
+ | |||
+ | ==== Dynamisches SQL mit Execute immediate ==== | ||
+ | Mit " | ||
+ | <code plsql> | ||
+ | declare | ||
+ | -- dynamic sql text statments | ||
+ | | ||
+ | | ||
+ | | ||
+ | -- | ||
+ | | ||
+ | begin | ||
+ | -- call sql statement with bind variable and returning value | ||
+ | -- Insert | ||
+ | execute | ||
+ | DBMS_OUTPUT.put_line(' | ||
+ | DBMS_OUTPUT.put_line(' | ||
+ | | ||
+ | -- Delete | ||
+ | execute immediate ' | ||
+ | DBMS_OUTPUT.put_line(' | ||
+ | |||
+ | commit; | ||
+ | | ||
+ | -- Select | ||
+ | execute immediate ' | ||
+ | DBMS_OUTPUT.put_line(' | ||
+ | |||
+ | end; | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | ==== Bulk Collect | ||
+ | |||
+ | Mit dem Bulk Collect Feature können große Updates / Inserts hoch performant zusammen gefasst werden: | ||
+ | <code plsql> | ||
+ | set serveroutput on | ||
+ | declare | ||
+ | -- declae table for the resuls | ||
+ | type t_emp_tab is table of emp%rowtype; | ||
+ | -- define | ||
+ | v_emptab t_emp_tab; | ||
+ | v_count pls_integer; | ||
+ | -- weak cursor | ||
+ | c_cur sys_refcursor; | ||
+ | begin | ||
+ | -- Cursor example Select | ||
+ | open c_cur for ' | ||
+ | fetch c_cur bulk collect into v_emptab; | ||
+ | close c_cur; | ||
+ | dbms_output.put_line(' | ||
+ | | ||
+ | -- Execute immediate Select | ||
+ | execute immediate ' | ||
+ | dbms_output.put_line(' | ||
+ | |||
+ | -- Manipulate the data in the memory | ||
+ | v_count := v_emptab.first; | ||
+ | while v_count is not null | ||
+ | loop | ||
+ | v_emptab(v_count).sal: | ||
+ | v_count := v_emptab.next(v_count); | ||
+ | end loop; | ||
+ | | ||
+ | -- | ||
+ | -- execute immedate update for all | ||
+ | forall i in 1 .. v_emptab.count | ||
+ | | ||
+ | | ||
+ | | ||
+ | -- | ||
+ | -- commit all 10 rows between | ||
+ | OPEN c_cur for ' | ||
+ | LOOP | ||
+ | FETCH c_cur BULK COLLECT INTO v_emptab LIMIT 10; | ||
+ | |||
+ | EXIT WHEN v_emptab.count=0; | ||
+ | |||
+ | forall i in 1 .. v_emptab.count | ||
+ | INSERT INTO emp.fact VALUES v_emptab(i); | ||
+ | commit; | ||
+ | | ||
+ | END LOOP; | ||
+ | CLOSE c_cur; | ||
+ | |||
+ | end; | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | siehe auch [[prog: | ||
+ | ==== Execute Immediate mit PLSQL Out Variable ==== | ||
+ | |||
+ | Mit " | ||
+ | |||
+ | Beispiel: | ||
+ | <code sql> | ||
+ | var OS varchar2(5) | ||
+ | declare | ||
+ | | ||
+ | begin | ||
+ | : | ||
+ | if ( SYS_CONTEXT(' | ||
+ | then | ||
+ | | ||
+ | if instr(v_oracle_home,'/' | ||
+ | : | ||
+ | else | ||
+ | : | ||
+ | end if; | ||
+ | end if; | ||
+ | end; | ||
+ | / | ||
+ | print OS | ||
+ | |||
+ | </ | ||
+ | |||
+ | ==== DBMS_SQL - dynamisches SQL ==== | ||
+ | |||
+ | Etwas umständlicher, | ||
+ | <code plsql> | ||
+ | declare | ||
+ | type curtype is ref cursor; | ||
+ | src_cur | ||
+ | v_cursor_id | ||
+ | v_colType_var | ||
+ | v_colType_num | ||
+ | v_colType_date date; | ||
+ | v_tab_desc | ||
+ | v_col_count | ||
+ | v_sql varchar2(1000) := ' | ||
+ | begin | ||
+ | |||
+ | dbms_output.put_line(rpad(' | ||
+ | dbms_output.put_line(rpad(rpad(' | ||
+ | dbms_output.put_line(rpad(' | ||
+ | |||
+ | -- open cursor for the sql statement | ||
+ | open src_cur for v_sql; | ||
+ | |||
+ | -- switch from native dynamic sql to dbms_sql package. | ||
+ | v_cursor_id := dbms_sql.to_cursor_number(src_cur); | ||
+ | dbms_sql.describe_columns(v_cursor_id, | ||
+ | |||
+ | -- define columns. | ||
+ | for i in 1 .. v_col_count | ||
+ | loop | ||
+ | if v_tab_desc(i).col_type = 2 then | ||
+ | dbms_sql.define_column(v_cursor_id, | ||
+ | elsif v_tab_desc(i).col_type = 12 then | ||
+ | dbms_sql.define_column(v_cursor_id, | ||
+ | else | ||
+ | dbms_sql.define_column(v_cursor_id, | ||
+ | end if; | ||
+ | end loop; | ||
+ | |||
+ | -- fetch rows with dbms_sql package. | ||
+ | while dbms_sql.fetch_rows(v_cursor_id) > 0 | ||
+ | loop | ||
+ | for i in 1 .. v_col_count | ||
+ | loop | ||
+ | | ||
+ | | ||
+ | if (v_tab_desc(i).col_type = 1) then | ||
+ | dbms_sql.column_value(v_cursor_id, | ||
+ | dbms_output.put_line(v_colType_var); | ||
+ | elsif (v_tab_desc(i).col_type = 2) then | ||
+ | dbms_sql.column_value(v_cursor_id, | ||
+ | dbms_output.put_line(v_colType_num); | ||
+ | elsif (v_tab_desc(i).col_type in ( 12 ) ) then --, 178, 179, 180, 181, 231 | ||
+ | dbms_sql.column_value(v_cursor_id, | ||
+ | dbms_output.put_line(v_colType_date); | ||
+ | else | ||
+ | | ||
+ | end if; | ||
+ | end loop; | ||
+ | | ||
+ | dbms_output.put_line(rpad(' | ||
+ | | ||
+ | end loop; | ||
+ | |||
+ | -- Close the cursor | ||
+ | dbms_sql.close_cursor(v_cursor_id); | ||
+ | |||
+ | end; | ||
+ | / | ||
+ | </ | ||
+ | In diesen Beispiel wird eine Tabelle in Spalten Ansicht ausgegeben, siehe auch aus der Script Library: | ||
+ | [[https:// | ||
+ | |||
+ | Weiteres Beispiel [[prog: | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ==== PL/SQL conditional compilation ==== | ||
+ | |||
+ | ** Seit 10.1.0.4 ** | ||
+ | |||
+ | Mit Conditional Compilation kann mit PreCompiler Statements noch zusätzliche Logik in PL/SQL hinterlegt werden. | ||
+ | |||
+ | In der Umgebung von PL/SQL können Compiler Flags gesetzt werden, diese Flags können abgefragt werden. | ||
+ | |||
+ | Je nach Laufzeitumgebung wird der Code dann anders übersetzt, sehr praktisch um Features für verschiedene Relases im selben Code zuverwenden, | ||
+ | |||
+ | Beispiel: | ||
+ | <code plsql> | ||
+ | ... | ||
+ | | ||
+ | is | ||
+ | select * from dept org | ||
+ | ---debug run | ||
+ | $if $$USE_TST_SETS=1 $then | ||
+ | where rownum < 5 | ||
+ | $end | ||
+ | order by DEPTNAME desc ; | ||
+ | ... | ||
+ | |||
+ | |||
+ | -------------- | ||
+ | -- Setzen mit PLSQL_CCFlags | ||
+ | -- | ||
+ | alter package export compile PLSQL_CCFlags = ' | ||
+ | |||
+ | |||
+ | -- teste mit | ||
+ | |||
+ | SET SERVEROUTPUT ON SIZE UNLIMITED | ||
+ | |||
+ | BEGIN | ||
+ | DBMS_PREPROCESSOR.print_post_processed_source ( | ||
+ | object_type => ' | ||
+ | schema_name => ' | ||
+ | object_name => ' | ||
+ | END; | ||
+ | / | ||
+ | |||
+ | | ||
+ | </ | ||
+ | |||
+ | siehe dazu: | ||
+ | * http:// | ||
+ | * https:// | ||
+ | |||
+ | |||
+ | Sehr praktisch sind dabei diese Direktiven um Debug Messages mit mehr Informationen auszustatten: | ||
+ | |||
+ | |||
+ | * $$PLSQL_LINE : Zeilennummer, | ||
+ | * $$PLSQL_UNIT : Name der aktuellen PL/SQL Unit | ||
+ | |||
+ | |||
+ | Mit 12c: | ||
+ | |||
+ | * $$PLSQL_UNIT_OWNER : Eigentümer | ||
+ | * $$PLSQL_UNIT_TYPE : Der Typ (procedure, function, package etc.) der aktuellen PL/SQL Unit | ||
+ | |||
+ | |||
+ | |||
+ | ---- | ||
+ | ===== Weitere Quellen über PL/SQL ===== | ||
+ | |||
+ | |||
+ | Der Guru - Steven Feuerstein: | ||
+ | * http:// | ||
+ | * http:// | ||
+ | |||
+ | |||
+ | Im Web: | ||
+ | * http:// | ||
prog/plsql_code_pices.txt · Zuletzt geändert: 2019/02/12 11:14 von gpipperr