2009-06-23 11 views
26

A la luz de la serie de preguntas "Hidden features of...", ¿qué características poco conocidas de PL/SQL le han resultado útiles?Funciones ocultas de PL/SQL

Editar: Las características específicas de PL/SQL son preferibles a las características de la sintaxis SQL de Oracle. Sin embargo, debido a que PL/SQL puede usar la mayoría de las construcciones de SQL de Oracle, pueden incluirse si facilitan la programación en PL/SQL.

+0

¿Está incluyendo SQL? Eso es todo un tema en sí mismo. –

+0

Preferiría construcciones de procedimientos PL/SQL. Sin embargo, las construcciones de SQL que solo se pueden encontrar en Oracle también califica algo, ya que se pueden llamar desde bloques PL/SQL. –

Respuesta

24

Puede anular las variables, puede nombrar bloques anónimos, y todavía se puede hacer referencia a las variables anulado por nombre:

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

¡Ni siquiera sabía que los bloques pudieran tener etiquetas! ¡Muy útil! –

+1

Es cierto. Muchos no saben que podemos etiquetar bucles. Realmente bueno. – Guru

+0

Agradable. No sabía la etiqueta del bloque – PVH

13

Una característica poco conocida con la que he tenido mucho éxito es la capacidad de insertar en una tabla utilizando una variable declarada como %ROWTYPE. Por ejemplo:

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; 

A pesar de que mastica un poco más de espacio de tabla de rehacer, sin duda hace que la inserción de datos (especialmente en las tablas más grandes) mucho más clara. También evita la multitud de variables necesarias para almacenar el valor de cada columna que desea insertar.

+0

% ROWTYPE guarda en la duplicación. – RichardOD

10

Tal vez no oculta lo suficiente, pero me encanta la Combinar declaración que permita realizar upserts (inserción o actualización)

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 no es PL/SQL (3GL) sino una declaración SQL de Oracle. –

+1

MERGE es parte del estándar SQL: 2003, y está disponible en la mayoría de las grandes plataformas. Aún así, muy útil y poco utilizado. – Martin

15

La función Oracle verdad oculta es la función se superpone, pero probablemente no es muy sabia usar cualquier característica no compatible.

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

Es una pena que no esté documentado. ¡Es tan claro y conciso! –

+0

Me pregunto si se puede usar directamente en las sentencias PL/SQL IF ... –

+1

Paynter: sí - begin if (sysdate-5, sysdate) se superpone (sysdate-2, sysdate-1) luego dbms_output.put_line (' sí'); final si; final; –

7

Este a/SQL constructo procedimiento PL yo uso mucho (créditos a Steven Feuerstein y Chen Shapira). Una matriz asociativa utilizada para chatear, pero no carga todos los datos, pero obtiene datos de la base de datos si es necesario y los coloca en la matriz asociativa.

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; 

prueba que:

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

¡Esos tipos de tablas son muy útiles! Me gusta poder usar índices arbitrarios (en tu caso, códigos de pelo) para hacer referencia a sus filas. ¡Mucho mejor que las matrices tradicionales! –

6
  1. Una función no documentada: dbms_system.ksdwrt (escribe para alertar a los archivos/traza)
  2. paquete DBMS_SQL (como un ejemplo de su uso ver this question
  3. AUTHID CURRENT_USER cláusula
  4. Conditional compilation
+0

Tenga cuidado al usar dbms_system.ksdwrt(). Los programas que lo usan pueden servir como vectores en un ataque DoS. – APC

+0

Característica oculta: la compilación condicional se puede habilitar en Oracle 9.2.0.6 (fue respaldada para admitir una versión de parche) – JulesLt

17

Puede indexar tablas pl/sql por otros tipos además de números enteros. De esta manera se puede crear "diccionario" como las estructuras, lo cual puede hacer que el código mucho más fácil de leer:

Ejemplo:

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

Una vez más, ¡otra cosa que no sabía que podía hacer! ¡Muy útil! –

4

dinámico PL/SQL es feo, pero puede hacer algunas cosas interesantes. Por ejemplo, los nombres pueden tratarse como variables, que he usado anteriormente para recorrer variables% rowtype como matrices, y para crear una función que, para un nombre de tabla dado, devolverá un cursor que selecciona una sola fila con los valores predeterminados de cada columna Ambas son soluciones útiles para tablas desnormalizadas.

10

Mi respuesta a Hidden Features in Oracle es relevante aquí:

Desde Apex es ahora parte de cada base de datos Oracle, estas funciones de utilidad Apex son útiles incluso si no está utilizando 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

nope .. apex no es 'estándar' ... en Oracle Database 10g Enterprise Edition Versión 10.2.0.4.0 - 64bi PL/SQL Release 10.2.0.4.0 - Producción a "desc apex_util" da ERROR: ORA-04043: objeto apex_util no existe – ShoeLace

+1

@ShoeLace, de hecho creo que ha sido estándar desde 10.2 al menos. Sin embargo, (a) el paquete aún se puede haber llamado htmldb_util, y (b) puede requerir configuración por parte del DBA para que esté disponible. No sé la respuesta definitiva a cualquiera de estas preguntas, me temo. –

12

Procedimientos y funciones pueden ser definidas dentro de DECLARE bloques:

DECLARE 

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

BEGIN 

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

END; 

Esto es útil para la creación de secuencias de comandos independientes.

+3

También puede anidar procedimientos y funciones, lo que es especialmente útil cuando necesita dividir los procedimientos grandes en varios más pequeños, sin pasar toneladas de parámetros. –

12

¿Sabía que con la opción SAMPLE (K) puede SELECCIONAR solo una muestra compuesta por hasta un K por ciento de una tabla de Oracle?

SELECT * 
    FROM MASSIVE_TABLE SAMPLE (5); 

La declaración anterior recupera un conjunto randomic compuesta por hasta un 5% de los registros almacenados en la tabla masiva llamada MASSIVE_TABLE.

+6

Esto no es PL/SQL. –

3

Se puede simular un continuar añadiendo una etiqueta a un bucle y luego un GOTO esta etiqueta:

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;