2009-06-23 14 views
26

Angesichts der Reihe von Fragen "Hidden features of...", welche wenig bekannten Funktionen von PL/SQL haben sich für Sie nützlich?Versteckte Funktionen von PL/SQL

Edit: PL/SQL-spezifische Funktionen werden den Funktionen der Oracle-SQL-Syntax vorgezogen. Da PL/SQL jedoch die meisten SQL-Konstrukte von Oracle verwenden kann, können sie einbezogen werden, wenn sie die Programmierung in PL/SQL erleichtern.

+0

Sind auch Sie SQL? Das ist ein ganz anderes Thema an sich. –

+0

Ich würde PL/SQL prozedurale Konstrukte bevorzugen. Allerdings sind SQL-Konstrukte, die nur in Oracle zu finden sind, ebenfalls einigermaßen geeignet, da sie aus PL/SQL-Blöcken aufgerufen werden können. –

Antwort

24

Sie Variablen außer Kraft setzen können, Sie anonyme Blöcke nennen kann, und Sie können immer noch nach dem Namen der außer Kraft gesetzten Variablen beziehen:

PROCEDURE myproc IS 
    n NUMBER; 
BEGIN 
    n := 1; 
    <<anon>> 
    DECLARE 
     n NUMBER; 
    BEGIN 
     n := 2; 
     dbms_output.put_line('n=' || n); 
     dbms_output.put_line('anon.n=' || anon.n); 
     dbms_output.put_line('myproc.n=' || myproc.n); 
    END anon; 
END myproc; 
+1

habe ich nicht einmal wissen, dass Blöcke Etiketten haben könnte! Sehr hilfreich! –

+1

Wahr. Viele wissen nicht, dass wir Schleifen beschriften können. Wirklich gut. – Guru

+0

Schön. Ich wusste nicht, Block-Label – PVH

13

Eine wenig bekannte Funktion, mit der ich großen Erfolg hatte, ist die Möglichkeit, sie in eine Tabelle einzufügen, die eine Variable verwendet, die als %ROWTYPE deklariert ist. Zum Beispiel:

CREATE TABLE CUSTOMERS (
    id NUMBER, 
    name VARCHAR2(100), 
    birth DATE, 
    death DATE 
) 

PROCEDURE insert_customer IS 
    customer CUSTOMERS%ROWTYPE; 
BEGIN 
    customer.id := 45; 
    customer.name := 'John Smith'; 
    customer.birth := TO_DATE('1978/04/03', 'YYYY/MM/DD'); 

    INSERT INTO CUSTOMERS VALUES customer; 
END; 

Obwohl es ein bisschen mehr Redo-Tabellen kaut, macht es sicherlich Einfügen von Daten (vor allem in größere Tabellen) viel klarer. Es vermeidet auch die Vielzahl der Variablen, die benötigt werden, um den Wert jeder Spalte zu speichern, den Sie einfügen möchten.

+0

% ROWTYPE spart bei der Duplizierung. – RichardOD

10

Vielleicht nicht genug versteckt, aber ich liebe die Anweisung Merge, die upserts (Insert oder Update)

MERGE <hint> INTO <table_name> 
USING <table_view_or_query> 
ON (<condition>) 
WHEN MATCHED THEN <update_clause> 
DELETE <where_clause> 
WHEN NOT MATCHED THEN <insert_clause> 
[LOG ERRORS <log_errors_clause> <reject limit <integer | unlimited>]; 
+6

MERGE ist nicht PL/SQL (3GL), sondern eine Oracle SQL-Anweisung. –

+1

MERGE ist Teil der SQL: 2003-Standard und auf den meisten der großen Plattformen. Immer noch sehr nützlich und wenig genutzt. – Martin

15

Die wirklich versteckt Orakel Funktion ist die OVERLAPS Funktion machen lassen, aber es ist wahrscheinlich nicht sehr klug um nicht unterstützte Funktionen zu verwenden.

select 'yes' from dual where (sysdate-5,sysdate) overlaps (sysdate-2,sysdate-1); 
+1

Es ist schade, dass es nicht dokumentiert ist. Es ist so klar und prägnant! –

+0

Ich frage mich, ob es direkt in PL/SQL-IF-Anweisungen verwendet werden kann ... –

+1

Paynter: ja - beginne wenn (Sysdate-5, Sysdate) überlappt (Sysdate-2, Sysdate-1) dann dbms_output.put_line (' Ja'); Ende wenn; Ende; –

7

Dies ist ein PL/SQL prozedurale Konstrukt ich eine Menge (Gutschriften Steven Feuerstein und Chen Shapira). Ein assoziatives Array, das zum Chaching verwendet wird, aber es lädt nicht alle Daten vor, sondern ruft bei Bedarf Daten aus der Datenbank ab und speichert sie im assoziativen Array.

create or replace 
PACKAGE justonce 
IS 
    FUNCTION hair (code_in IN hairstyles.code%TYPE) 
    RETURN hairstyles%ROWTYPE; 
    TYPE hair_t IS TABLE OF hairstyles%ROWTYPE 
    INDEX BY BINARY_INTEGER; 
    hairs   hair_t; 
END justonce; 

create or replace 
PACKAGE BODY justonce 
IS 
    FUNCTION hair (code_in IN hairstyles.code%TYPE) RETURN hairstyles%ROWTYPE 
    IS 
    return_value hairstyles%ROWTYPE; 
    FUNCTION hair_from_database RETURN hairstyles%ROWTYPE 
    IS 
     CURSOR hair_cur IS 
     SELECT * FROM hairstyles WHERE code = code_in; 
    BEGIN 
     OPEN hair_cur; 
     FETCH hair_cur INTO return_value; 
     CLOSE hair_cur; 
     RETURN return_value; 
    END hair_from_database; 
    BEGIN 
    IF NOT (hairs.exists(code_in)) 
    THEN 
     dbms_output.put_line('Get record from database'); 
     hairs (code_in) := hair_from_database; 
    END IF; 
    RETURN hairs (code_in); 
    END hair; 
END justonce; 

Test-it:

declare 
    h hairstyles%ROWTYPE; 
begin 
    for i in 1000..1004 
    loop 
     h := justonce.hair(i); 
     dbms_output.put_line(h.description); 
    end loop; 
    for i in 1000..1004 
    loop 
     h := justonce.hair(i); 
     dbms_output.put_line(h.description||' '||h.price); 
    end loop; 

end; 
/

Get record from database 
CREWCUT 
Get record from database 
BOB 
Get record from database 
SHAG 
Get record from database 
BOUFFANT 
Get record from database 
PAGEBOY 
CREWCUT 10 
BOB 20 
SHAG 21 
BOUFFANT 11 
PAGEBOY 44 
+1

Diese Tabellentypen sind sehr nützlich! Ich mag es, in der Lage zu sein, beliebige Indizes (in Ihrem Fall, Haar-Codes) zu verwenden, um seine Reihen zu verweisen. Viel schöner als traditionelle Arrays! –

6
  1. eine nicht dokumentierte Funktion: dbms_system.ksdwrt (schreibt/Trace-Dateien zu alarmieren)
  2. DBMS_SQL Paket (als Beispiel für seine Verwendung finden this question
  3. AUTHID CURRENT_USER-Klausel
  4. Conditional compilation
+0

Seien Sie vorsichtig bei der Verwendung von dbms_system.ksdwrt(). Programme, die es verwenden, können als Vektoren in einem DoS-Angriff dienen. – APC

+0

Versteckte Funktion: Bedingte Kompilierung kann in Oracle 9.2.0.6 aktiviert werden (es wurde zurück portiert, um eine Patch-Version zu unterstützen) – JulesLt

17

Sie können PL/SQL-Tabellen auch nach anderen Typen als ganze Zahlen indizieren. Auf diese Weise können „Wörterbuch“ artige Strukturen schaffen, die Ihr Code viel einfacher machen können zu lesen:

Beispiel:

DECLARE 
    TYPE dictionary IS TABLE OF VARCHAR2(200) INDEX BY VARCHAR2(100); 
    dict dictionary; 
BEGIN 
    dict('NAME') := 'John Doe'; 
    dict('CITY') := 'New York'; 

    dbms_output.put_line('Name:' || dict('NAME')); 
END; 
+2

Wieder eine andere Sache, die ich nicht wusste, dass Sie tun könnten! Sehr hilfreich! –

4

Dynamische PL/SQL ist hässlich, aber einige interessante Dinge tun. Zum Beispiel können Namen als Variablen behandelt werden, die ich früher zum Durchlaufen von% -Zeilenvariablen wie Arrays verwendet habe, und um eine Funktion zu erstellen, die für einen bestimmten Tabellennamen einen Cursor zurückgibt, der eine einzelne Zeile mit den Standardwerten auswählt jeder Spalte. Beide sind nützliche Umgehungslösungen für denormalisierte Tabellen.

10

Meine Antwort auf Hidden Features in Oracle ist hier relevant:

Seit Apex jetzt Bestandteil jeder Oracle-Datenbank ist, sind diese Apex Utility-Funktionen nützlich, selbst wenn Sie nicht verwenden Apex:

SQL> declare 
    2 v_array apex_application_global.vc_arr2; 
    3 v_string varchar2(2000); 
    4 begin 
    5 
    6 -- Convert delimited string to array 
    7 v_array := apex_util.string_to_table('alpha,beta,gamma,delta', ','); 
    8 for i in 1..v_array.count 
    9 loop 
10  dbms_output.put_line(v_array(i)); 
11 end loop; 
12 
13 -- Convert array to delimited string 
14 v_string := apex_util.table_to_string(v_array,'|'); 
15 dbms_output.put_line(v_string); 
16 end; 
17/
alpha 
beta 
gamma 
delta 
alpha|beta|gamma|delta 

PL/SQL procedure successfully completed. 
+1

Nein .. Apex isnt 'Standard' .. auf Oracle-Datenbank 10g Enterprise Edition Version 10.2.0.4.0 - 64bi PL/SQL Release 10.2.0.4.0 - Produktion ein "desc apex_util" gibt ERROR: ORA-04043: Objekt apex_util existiert nicht – ShoeLace

+1

@ShoeLace, eigentlich glaube ich es seit 10.2 zumindest Standard war. Jedoch (a) könnte das Paket dann immer noch htmldb_util heißen, und (b) es könnte eine Konfiguration durch den DBA erfordern, um es verfügbar zu machen. Ich kenne die endgültige Antwort auf eine dieser Fragen leider nicht. –

12

Verfahren und

DECLARE 

    PROCEDURE print(text VARCHAR2) IS 
    BEGIN 
     DBMS_OUTPUT.put_line(text); 
    END; 

BEGIN 

    print('Yay!'); 
    print('Woo hoo!'); 

END; 

Das ist praktisch für die Erstellung von Stand-alone-Skripte: Funktionen können innerhalb DECLARE Blöcke definiert werden.

+3

Sie können auch Prozeduren und Funktionen verschachteln, was besonders nützlich ist, wenn Sie große Prozeduren in mehrere kleinere zerlegen müssen, ohne eine Unmenge von Parametern zu übergeben. –

12

Wissen Sie, dass mit der Option SAMPLE (K) nur eine Probe von oben zusammengesetzt SELECT kann Prozent einer Oracle-Tabelle K?

SELECT * 
    FROM MASSIVE_TABLE SAMPLE (5); 

Die vorhergehende Anweisung ruft einen randomic Satz um bis zu 5% der in der Tabelle gespeichert massiven Aufzeichnungen zusammengesetzt MASSIVE_TABLE genannt.

+6

Dies ist nicht PL/SQL. –

3

Sie können eine um eine Bezeichnung zu einer Schleife und dann ein GOTO dieses Label WEITER simulieren:

declare 
    i integer; 
begin 
    i := 0; 

    <<My_Small_Loop>>loop 

     i := i + 1; 
     if i <= 3 then goto My_Small_Loop; -- => means continue 
     end if; 

     exit; 

    end loop; 
end;