2009-06-23 15 views
26

Alla luce delle serie di domande "Hidden features of...", quali funzionalità poco note di PL/SQL sono diventate utili per voi?Funzioni nascoste di PL/SQL

Modifica: Le funzioni specifiche di PL/SQL sono preferite rispetto alle funzioni della sintassi SQL di Oracle. Tuttavia, poiché PL/SQL può utilizzare la maggior parte dei costrutti SQL di Oracle, possono essere inclusi se rendono più semplice la programmazione in PL/SQL.

+0

Stai tra cui SQL? Questo è un intero argomento di per sé. –

+0

Preferirei i costrutti procedurali PL/SQL. Tuttavia, i costrutti SQL che possono essere trovati solo in Oracle sono in qualche modo qualificati in quanto possono essere chiamati da blocchi PL/SQL. –

risposta

24

È possibile ignorare le variabili, è possibile denominare blocchi anonimi, ed è ancora possibile fare riferimento alle variabili override per nome:

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

Non sapevo nemmeno che i blocchi potevano avere etichette! Molto utile! –

+1

Vero. Molti non sanno che possiamo etichettare i loop. Veramente buono. – Guru

+0

Bello. Non conoscevo l'etichetta del blocco – PVH

13

Una caratteristica poco conosciuta con cui ho avuto un grande successo è la possibilità di inserire in una tabella utilizzando una variabile dichiarata come %ROWTYPE. Ad esempio:

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; 

Sebbene mastica un po 'più rifare tablespace, rende sicuramente inserimento dati (specialmente in tabelle più grandi) molto più chiara. Evita anche la moltitudine di variabili necessarie per memorizzare il valore di ogni colonna che si desidera inserire.

+0

% ROWTYPE salva sulla duplicazione. – RichardOD

10

Forse non nascosto a sufficienza, ma amo il Merge dichiarazione che permettono rendere upserts (inserimento o aggiornamento)

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 non è PL/SQL (3GL) ma un'istruzione Oracle SQL. –

+1

MERGE fa parte dello standard SQL: 2003 e disponibile sulla maggior parte delle piattaforme principali. Ancora, molto utile e sottoutilizzato. – Martin

15

La funzione di oracolo veramente nascosto è la funzione si sovrappone, ma probabilmente non è molto saggia per utilizzare le funzioni non supportate.

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

È un peccato che non sia documentato. È così chiaro e conciso! –

+0

Mi chiedo se possa essere utilizzato direttamente nelle istruzioni IF PL/SQL ... –

+1

Paynter: sì - begin if (sysdate-5, sysdate) si sovrappone (sysdate-2, sysdate-1) quindi dbms_output.put_line (' sì'); fine se; fine; –

7

Questo un costrutto procedurale PL/SQL uso molto (crediti a Steven Feuerstein e Chen Shapira). Un array associativo utilizzato per la chaching, ma non precarica tutti i dati ma ottiene i dati dal database se necessario e li inserisce nell'array associativo.

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; 

prova è:

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

Questi tipi di tabelle sono molto utili! Mi piace essere in grado di utilizzare indici arbitrari (nel tuo caso, codici hair) per fare riferimento alle sue righe. Molto più bello degli array tradizionali! –

6
  1. Una funzione non documentata: dbms_system.ksdwrt (scrive per avvisare i file/traccia)
  2. pacchetto DBMS_SQL (come un esempio del suo utilizzo vedi this question
  3. clausola AUTHID CURRENT_USER
  4. Conditional compilation
+0

Fare attenzione sull'utilizzo di dbms_system.ksdwrt(). I programmi che lo utilizzano possono fungere da vettori in un attacco DoS. – APC

+0

Funzionalità nascosta: la compilazione condizionale può essere abilitata in Oracle 9.2.0.6 (era back-ported per supportare una versione patch) – JulesLt

17

È possibile indicizzare tabelle pl/sql con altri tipi oltre agli interi. In questo modo è possibile creare "dizionario" come le strutture, in grado di rendere il codice più facile da leggere:

Esempio:

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

Ancora, un'altra cosa che non sapevo che potessi fare! Molto utile! –

4

dinamico PL/SQL è brutto, ma può fare alcune cose interessanti. Ad esempio, i nomi possono essere trattati come variabili, che ho usato in precedenza per attraversare% variabili rowtype come matrici, e per creare una funzione che restituirà un cursore per un dato nome di tabella, che seleziona una singola riga con i valori predefiniti di ogni colonna. Entrambi sono soluzioni alternative utili per le tabelle denormalizzate.

10

La mia risposta a Hidden Features in Oracle è rilevante qui:

Dal Apex è ora parte di tutti i database Oracle, queste funzioni di utilità Apex sono utili anche se non si sta utilizzando 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

no .. apex non è "standard" .. su Oracle Database 10g versione Enterprise 10.2.0.4.0 - 64bi PL/SQL versione 10.2.0.4.0 - Produzione un "disc apex_util" dà ERRORE: ORA-04043: oggetto apex_util non esiste – ShoeLace

+1

@ShoeLace, in realtà credo che è normale dal 10,2 almeno. Tuttavia (a) il pacchetto potrebbe essere stato ancora chiamato htmldb_util, quindi (b) potrebbe richiedere la configurazione da parte del DBA per renderlo disponibile. Non conosco la risposta definitiva a nessuna di queste domande, temo. –

12

procedure e funzioni possono essere definite entro DECLARE blocchi:

DECLARE 

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

BEGIN 

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

END; 

Questo è utile per la creazione di script stand-alone.

+3

È inoltre possibile nidificare procedure e funzioni, che è particolarmente utile quando è necessario suddividere procedure di grandi dimensioni in diverse più piccole, senza passare tonnellate di parametri. –

12

Sai che con l'opzione SAMPLE (K) puoi SELEZIONARE solo un campione composto da fino al K percento di una tabella Oracle?

SELECT * 
    FROM MASSIVE_TABLE SAMPLE (5); 

La precedente dichiarazione recupera un set composto da randomica fino al 5% dei record memorizzati nella tabella massiccia chiamato MASSIVE_TABLE.

+6

Questo non è PL/SQL. –

3

È possibile simulare una proseguire con l'aggiunta di un'etichetta per un ciclo e poi un GOTO questa etichetta:

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;