2010-04-26 15 views
10

Quiero ejecutar una consulta SQL dentro de PL/SQL y completar los resultados en una matriz asociativa, donde una de las columnas en el SQL se convierte en la clave de la matriz asociativa. Por ejemplo, decir que tengo una tabla con columnas PersonPL/SQL bulk recopilar en matriz asociativa con clave dispersa

PERSON_ID INTEGER  PRIMARY KEY 
PERSON_NAME VARCHAR2(50) 

... y los valores como:

PERSON_ID | PERSON_NAME 
------------------------ 
6   | Alice 
15   | Bob 
1234  | Carol 

quiero mayor recoger esta tabla en un TABLE OF VARCHAR2(50) INDEX BY INTEGER tal que la clave 6 en este asociativo array tiene el valor Alice y así sucesivamente. ¿Se puede hacer esto en PL/SQL? ¿Si es así, cómo?

Respuesta

14

No, debe usar 2 colecciones (id, nombre) o una cuyo tipo de elemento sea un registro.

He aquí una muestra de este último:

cursor getPersonsCursor is 
    SELECT ID, Name 
    FROM Persons 
    WHERE ...; 

    subtype TPerson is getPersonsCursor%rowtype; 
    type TPersonList is table of TPerson; 
    persons TPersonList; 
begin 

open getPersonsCursor; 
fetch getPersonsCursor 
    bulk collect into persons; 
close getPersonsCursor; 

if persons.Count > 0 then 
    for i in persons.First .. persons.Last loop 
    yourAssocArray(persons(i).ID) := persons(i).Name; 
    end loop; 
end if; 
+1

+1. Si el número de filas es (o alguna vez será) muy grande, considere usar una cláusula LIMIT para evitar el consumo excesivo de memoria PGA. –

+0

Sí, también hago eso para permitir una mejor escala. Aunque pensé que sería un poco exagerado. –

6

Si queremos especificar el valor en el índice de una matriz asociativa entonces tenemos que utilizar esta sintaxis:

SQL> declare 
    2  type n_array is table of varchar2(30) 
    3   index by binary_integer; 
    4  emp_names n_array; 
    5 begin 
    6  for r in (select ename, empno from emp) 
    7  loop 
    8   emp_names(r.empno) := r.ename; 
    9  end loop; 
10 
11  dbms_output.put_line('count='||emp_names.count() 
12        ||'::last='||emp_names.last()); 
13  dbms_output.put_line(emp_names(8085)); 
14 
15 end; 
16/
count=19::last=8085 
TRICHLER 

PL/SQL procedure successfully completed. 

SQL> 

Nos puede poblar matrices asociativas con recopilación masiva, pero solo si el índice es un número entero, y nos complace indexar (implícitamente) ROWNUM, es decir, no una clave dispersa ...

SQL> declare 
    2  type n_array is table of varchar2(30) 
    3   index by binary_integer; 
    4  emp_names n_array; 
    5 begin 
    6  select ename 
    7  bulk collect into emp_names 
    8  from emp ; 
    9 
10  dbms_output.put_line('count='||emp_names.count() 
11        ||'::last='||emp_names.last()); 
12  dbms_output.put_line(emp_names(19)); 
13 
14 end; 
15/
count=19::last=19 
FEUERSTEIN 

PL/SQL procedure successfully completed. 

SQL> 

Para ser justos, si necesita utilizar BULK COLLECT probablemente esté tratando con más datos de los apropiados para una matriz asociativa.

Editar

Una prueba de rendimiento económico-ish de los dos enfoques:

SQL> declare 
    2  type n_array is table of varchar2(30) 
    3   index by binary_integer; 
    4  emp_names n_array; 
    5  s_time pls_integer; 
    6  e_time pls_integer; 
    7 begin 
    8  s_time := dbms_utility.get_time; 
    9  select ename 
10  bulk collect into emp_names 
11  from big_emp 
12  where rownum <= 500; 
13  dbms_output.put_line('bulk collect elapsed time = ' 
14        ||to_char(dbms_utility.get_time - s_time)); 
15  s_time := dbms_utility.get_time; 
16  for r in (select ename, empno from big_emp 
17     where rownum <= 500) 
18  loop 
19   emp_names(r.empno) := r.ename; 
20  end loop; 
21  dbms_output.put_line('sparse array elapsed time = ' 
22        ||to_char(dbms_utility.get_time - s_time)); 
23 end; 
24/

bulk collect elapsed time = 0 
sparse array elapsed time = 0 

PL/SQL procedure successfully completed. 

SQL> 

pruebas de rendimiento del reloj de pared son notoriamente chungo. Pero para unos cientos de registros, no es probable que valga la pena preocuparse por ninguna diferencia, sin duda en el contexto del tipo de lugar en el que podríamos querer usar una matriz asociativa.

Editar 2

@ Dan dijo:

t parece a mí que querer consultar un número tamaño decente de filas en una estructura de datos que se puede utilizar para constante- búsqueda de tiempo debe ser una bastante común necesidad

Realmente depende de su definición de "un número de tamaño decente". ¿De verdad hay muchos casos en los que nos gustaría poblar una matriz asociativa con miles de filas, con un índice de cadena? Cuando llegamos a ese tipo de números, una tabla de base de datos normal puede ser igual de útil, especialmente en 11g Enterprise Edition with resultset caching.

+0

¿Cuántos es eso? Tengo entendido que, incluso para un número relativamente pequeño de filas (digamos unos cientos), la sobrecarga del conmutador de contexto de SQL a PL/SQL fue suficiente para utilizar BULK COLLECT. ¿Su primer ejemplo (para el bucle en un cursor) no tiene ese problema? – Dan

+2

Como aconseja el propio FEUERSTEIN, nunca utilice los bucles FOR del cursor a menos que se trate de un pequeño número de filas (cientos). (O simplemente no le importa un comino el rendimiento) –

+0

Hm. Bueno, entonces, ¿cuál es la respuesta correcta aquí? Me parece que querer consultar un número de filas de un tamaño decente en una estructura de datos que se puede utilizar para la búsqueda de tiempo constante debería ser una necesidad bastante común. – Dan

Cuestiones relacionadas