CREATE OR REPLACE	   
PACKAGE pkg_cheat_sheet AS	   
/*	   
   Dies ist ein mehrzeiliger Kommentartext:	   
   Alles in dieser Spezifikation Deklarierte ist für die Verwendung	   
   sichtbar und kann außerhalb dieses Packages benutzt werden.	   
*/	   
	   
-- Dies ist ein einzeiliger Kommentartext.	   
	   
TYPE t_refcursor IS REF CURSOR; -- Flexibler Cursor zur Verwendung	   
                                --   mit dynamischem SQL	   
	   
-- Eine Record-Definition	   
TYPE t_record_manually IS RECORD(	   
   empno  emp.empno%TYPE --   Übernimmt das Format der angesprochenen	   
                         --   Tabellenspalte und wird bei jedem Laden	   
                         --   des Packages aktualisiert.	   
  ,ename  VARCHAR2(200)  --   Muss bei Änderungen der Tabellenspalte	   
                         --   manuell nachgeführt werden.	   
  ,deptno NUMBER(10)     --   Das Package muss dann kompiliert werden.	   
); -- t_record_manually	   
	   
-- Eine PL/SQL Tabelle	   
TYPE t_collection IS TABLE OF VARCHAR2(8) INDEX BY BINARY_INTEGER;	   
	   
-- Zweidimensionales Array	   
TYPE t_2dim IS TABLE OF t_collection;	   
	   
-- Dreidimensionales Array	   
TYPE t_3dim IS TABLE OF t_2dim;	   
	   
-- Definition von Konstanten	   
UNIVERSELLE_ANTWORT CONSTANT PLS_INTEGER := 42;	   
	   
-- Eine Prozedurdefinition	   
PROCEDURE prc_demo(	   
   p_Ein_IN_Parameter     IN VARCHAR2	   
  ,p_Ein_INOUT_Parameter  IN OUT VARCHAR2	   
  ,p_2ter_INOUT_Parameter IN OUT NOCOPY VARCHAR2	   
  ,p_Ein_OUT_Parameter    OUT BOOLEAN -- hier ginge auch NOCOPY!	   
); -- prc_demo	   
	   
END pkg_cheat_sheet;	 
/
 
CREATE OR REPLACE	   
PACKAGE BODY pkg_cheat_sheet AS	   
	   
/* HIER KÖNNTE IHRE WERBUNG STEHEN */	   
	   
-- Funktionsdefinition; die Funktion "schon5" ist nur im Package 	   
--   pkg_cheat_sheet sichtbar, da sie nicht in der Spezifikation 	   
--   deklariert ist.	   
FUNCTION schon5(p_date IN DATE) RETURN BOOLEAN IS	   
  v_return BOOLEAN;	   
  BEGIN -- schon5	   
    -- Vergleichsergebnis in boolescher Variable ablegen	   
    v_return := to_number(to_char(p_date, 'HH24')) >= 17;	   
    RETURN v_return;	   
  END schon5;	   
	   
-- Wer diese Prozedur vor 17 Uhr startet, braucht etwas Geduld ...	   
-- ... oder ändert sie vorher.	   
PROCEDURE prc_demo(	   
   p_Ein_IN_Parameter     IN VARCHAR2	   
  ,p_Ein_INOUT_Parameter  IN OUT VARCHAR2	   
  ,p_2ter_INOUT_Parameter IN OUT NOCOPY VARCHAR2	   
  ,p_Ein_OUT_Parameter    OUT BOOLEAN -- hier ginge auch NOCOPY!	   
) IS	   
	   
  -- lokale Variablen für die Prozedur prc_demo	   
  v_greatnumber   NUMBER;       -- entspricht NUMBER(38),	   
                                --   38 Ziffern sind das Maximum	   
  v_precisenumber NUMBER(5,10); -- 5 Vorkomma- und 10 Nachkomma-	   
                                --   stellen, automatische Rundung	   
	   
  v_binary_integer     BINARY_INTEGER; -- Ab 10g identisch mit PLS_INTEGER	   
  v_binary_integer_min BINARY_INTEGER := -power(2,31)+1; -- -2147483648+1	   
  v_binary_integer_max BINARY_INTEGER :=  power(2,31)-1; --  2147483648-1	   
  	   
  v_pls_integer     PLS_INTEGER;    -- schnellste Verarbeitung bis 9i	   
  v_pls_integer_min PLS_INTEGER := -power(2,31)+1; -- -2147483648+1	   
  v_pls_integer_max PLS_INTEGER :=  power(2,31)-1; --  2147483648-1	   
	   
  v_char_onebyte      CHAR(1);         -- Zeichenkette der Länge 1 Byte	   
  v_char              CHAR(100 BYTE);  -- Zeichenkette der Länge 100 Byte	   
  v_char_multi        CHAR(100 CHAR);  -- Zeichenkette der Länge 100 	   
                                       -- Zeichen (zum Beispiel für Unicode)	   
  v_char_max_plsql    CHAR(32767 BYTE);-- Maximale Länge in PL/SQL	   
  v_char_max_database CHAR(2000  BYTE);-- Maximale Länge als Tabellenfeld	   
	   
  -- Zeichenkette mit dynamischer Speicherallokierung in PL/SQL	   
  v_varchar2              VARCHAR2(100); -- Default ist BYTE	   
  -- deklarierte Länge >= 2000 BYTE allokiert nur die genutzte Länge	   
  --   (zur Speicheroptimierung)	   
  v_varchar2_dynamic      VARCHAR2(2000 BYTE);	   
  -- deklarierte Länge < 2000 allokiert deklarierte Anzahl Bytes	   
  --   (zur Performance-Optimierung)	   
  v_varchar2_fix          VARCHAR2(1999 BYTE);	   
  -- Maximale Länge in PL/SQL	   
  v_varchar2_max_plsql    VARCHAR2(32767 BYTE);	   
  -- Maximale Länge als Feld einer Tabelle	   
  v_varchar2_max_database VARCHAR2(4000 BYTE);	   
	   
  v_date          DATE := sysdate; -- Datumsformat. Sysdate liefert das	   
                                   --   aktuelle Datum mit Uhrzeit	   
  v_date_min      DATE := to_date('01.01.-4712','DD.MM.SYYYY');	   
  v_date_max      DATE := to_date('31.12.9999 23:59:59',	   
                                  'DD.MM.YYYY HH24:MI:SS');	   
  v_chardate      VARCHAR2(2000) := to_char(to_date('01.01.-4712',	   
                                                    'DD.MM.SYYYY'),	   
                                            'DD.MM.YYYY AD');	   
  v_timestamp     TIMESTAMP(6) :=	   
                    to_timestamp('11.06.1965 13:37:00.001337',	   
                                 'DD.MM.YYYY HH24:MI:SS.FF6');	   
  v_chartimestamp VARCHAR2(2000) := 	   
                    to_char(to_timestamp('11.03.1964 13:37:00.001337',	   
                                         'DD.MM.YYYY HH24:MI:SS.FF6'),	   
                            'DD.MM.YYYY HH24:MI:SS.FF6');	   
  v_longtime      INTERVAL YEAR(3) TO MONTH;	   
  v_countdown     INTERVAL DAY(3) TO SECOND(6);	   
	   
  v_true          BOOLEAN := true;	   
  v_false         BOOLEAN := false;	   
	   
  -- Binärdaten, Länge immer in Byte, Inhalt ändert sich nicht 	   
  --   bei Zeichensatzkonvertierung (VARCHAR2 schon ...)	   
  v_raw              RAW(6502);	   
  v_raw_max_plsql    RAW(32767);-- In zwei davon passt ein C64 ...	   
  v_raw_max_database RAW(4000); -- In Tabellen gibt es noch LONG RAW, 	   
                                -- max. Länge dann 2^31 Bytes.	   
	   
  /* Wichtig!	   
     Passworte, die in VARCHAR2 oder CHAR statt RAW abgelegt sind, ändern 	   
     sich beim Zeichensatzwechsel oder bei der Übertragung in eine andere 	   
     Datenbank (mittels Import oder Datenbank-Link). So schnell kann man	   
     ein paar Tausend Benutzer aussperren ...	   
  */	   
	   
  -- Large OBjects, maximale Größe 4GB (ja, Gigabytes)	   
  v_lob  BLOB; -- Binary Large OBject, Binärdaten	   
  v_clob CLOB; -- Character Large OBject, Textdaten	   
	   
  /*	   
  LOB-Typen in PL/SQL speichern nur "Locators" (Pointer), die auf die 	   
  tatsächlichen Large OBjects in externen Files, in-line (als Feld in 	   
  einer Tabellenzeile) oder out-of-line (außerhalb der Tabellenzeile). 	   
  BLOB, CLOB, und NCLOB-Daten werden in der Datenbank abgelegt, 	   
  BFILE-Daten werden in normalen Files auf Betriebssystemebene abgelegt. 	   
  In LOB-Typen lassen sich zum Beispiel Dokumente oder Multimediafiles ablegen.	   
  Der Zugriff auf LOBs erfolgt mit dem Package DBMS_LOB.	   
  */	   
	   
  -- Einer Konstante kann im Ausführungsteil kein anderer Wert	   
  -- zugewiesen werden. - In diesem Fall eindeutig notwendig	   
  THE_ANSWER CONSTANT NUMBER(2) := 42;	   
	   
  -- Benutzerdefinierte EXCEPTIONS	   
  RAUSHIER EXCEPTION;	   
  PANIC    EXCEPTION;	   
	   
  -- Cursor ohne Parameter	   
  CURSOR c_emp IS	   
    SELECT empno	   
    ,      ename	   
    ,      job	   
    ,      mgr	   
    ,      hiredate	   
    ,      sal	   
    ,      comm	   
    ,      deptno	   
    FROM   emp;	   
	   
  -- Cursor mit Parameter	   
  CURSOR c_one_emp(p_empno emp.EMPNO%TYPE) IS	   
    SELECT *	   
    FROM   emp e	   
    WHERE  e.empno = p_empno; 	   
	   
  r_emp_cursor c_one_emp%ROWTYPE;	   
  r_emp_table  emp%ROWTYPE;	   
	   
  -- eingeschachtelte Prozedur, ist nur innerhalb von prc_demo sichtbar	   
  PROCEDURE nevercallme IS	   
    BEGIN -- nevercallme	   
      dbms_lock.sleep(2);	   
    END nevercallme;	   
	   
BEGIN -- prc_demo	   
	   
  -- *** Befehlsfolge *** Sequenz ***	   
  sys.dbms_lock.sleep(1); -- nur keine Hektik	   
  dbms_output.enable(100000); -- Debug-Ausgabe einschalten	   
  dbms_output.put_line('Und los!'); -- Nein, 'Hello world' nehmen wir    
-- nicht	   
  -- Basiseinheit 1 = 1 Tag, also 'DAY'	   
  v_countdown := numtodsinterval(trunc(sysdate,'DD') + 	   
                                 17/24 - sysdate, 'DAY');	   
  dbms_output.put_line('Takeoff in: ' || v_countdown);	   
	   
  -- *** Verzweigungen *** Alternative ***	   
  -- Einfaches IF	   
  IF true THEN	   
    NULL; -- ein NO OP	   
  END IF; 	   
	   
  -- Einfaches IF mit ELSE-Zweig	   
  IF schon5 (sysdate) THEN 	   
    RAISE RAUSHIER; -- verstecktes GOTO ...	   
  ELSE	   
    dbms_lock.sleep(1);	   
  END IF;	   
	   
  -- IF mit Mehrfachverzweigung und optionalem ELSE-Zweig	   
  IF 1=2 THEN	   
    nevercallme;	   
  ELSIF false THEN	   
    NULL;	   
  ELSE	   
    NULL;	   
  END IF;	   
	   
  -- Fallunterscheidung mit CASE	   
  CASE trim(to_char(sysdate, 'DAY'))	   
    WHEN 'MONTAG' THEN dbms_output.put_line('Das zieht sich ...');	   
    WHEN 'FREITAG' THEN dbms_output.put_line('TGIF');-- Thank God it's 
-- Friday	   
    ELSE dbms_output.put_line('Frag nicht ...');	   
  END CASE;	   
	   
	   
  -- *** Schleifen *** Iteration ***	   
	   
  -- WHILE-Schleife, Eintrittsbedingung oben im Schleifenkopf	   
  WHILE to_number(to_char(sysdate, 'HH24')) < 15 LOOP	   
    dbms_lock.sleep(60); -- Warten auf Dienstschluss ... 	   
  END LOOP;	   
	   
  v_pls_integer := 0;	   
  WHILE v_pls_integer < 10 LOOP -- nur rein, wenn Eintrittsbedingung 
-- erfüllt	   
    v_pls_integer := v_pls_integer + 1;	   
  END LOOP;	   
	   
  -- FOR-Schleife, feste Anzahl Durchläufe	   
  FOR counter IN 1..10 LOOP -- zählt rauf	   
    dbms_output.put_line(counter);	   
  END LOOP;	   
	   
  FOR i IN REVERSE 1..10 LOOP -- zählt runter	   
    dbms_output.put_line(i);	   
  END LOOP;	   
	   
  -- FOR-Schleife mit Cursor	   
  FOR rec IN c_emp LOOP	   
    dbms_output.put_line(rec.ename);	   
  END LOOP;	   
	   
  -- FOR-Schleife mit SELECT (impliziter Cursor)	   
  FOR rec IN (SELECT * FROM dept) LOOP	   
    dbms_output.put_line(rec.dname);	   
  END LOOP;	   
	   
  -- Schleife mit Austrittsbedingung	   
  v_pls_integer := 0;	   
  LOOP -- auf jeden Fall einmal rein	   
    v_pls_integer := v_pls_integer + 1;	   
    EXIT WHEN v_pls_integer >= 10; -- nur raus, wenn Austrittsbedingung	   
                                   -- erfüllt - wie REPEAT ... UNTIL	   
  END LOOP;	   
	   
  -- Einen bestimmten Datensatz mittels Cursor laden	   
  OPEN c_one_emp(7934); -- Max Miller, Private Investigations	   
  FETCH c_one_emp INTO r_emp_cursor;	   
  IF c_one_emp%FOUND THEN	   
    dbms_output.put_line('The Name is '||r_emp_cursor.ename);	   
  ELSE -- c_one_emp%NOTFOUND	   
    dbms_output.put_line('Gibts hier nicht!');	   
    CLOSE c_one_emp;	   
    RAISE PANIC;	   
  END IF;	   
  CLOSE c_one_emp;	   
	   
  -- Dynamic SQL (Vorsicht, automatisches COMMIT bei DDL)	   
  EXECUTE IMMEDIATE 'CREATE TABLE emp2 AS SELECT * FROM emp';	   
  EXECUTE IMMEDIATE 'TRUNCATE TABLE emp2';	   
  EXECUTE IMMEDIATE 'DROP TABLE emp2';	   
	   
  v_char_onebyte := 'This line never works'; --...but compiles fine	   
	   
EXCEPTION	   
  WHEN PANIC THEN	   
    dbms_output.put_line('Don''t panic!');  	   
  WHEN RAUSHIER THEN	   
    NULL; -- heimlich verabschieden	   
  WHEN OTHERS THEN	   
    CASE SQLCODE	   
      WHEN -6502 THEN dbms_output.put_line('Cornel was here ...');	   
      WHEN -1103 THEN dbms_output.put_line('Oh Frank, you again!');	   
      ELSE RAISE; -- nach oben weiterreichen. Make the boss panic ...	   
    END CASE;	   
    	   
END prc_demo; 	   
	   
END pkg_cheat_sheet;	 
/
