sql >> Base de Datos >  >> RDS >> Oracle

Acceda al cursor por nombre de columna dinámicamente

Puede usar el paquete DBMS_SQL para crear y acceder a cursores con consultas dinámicas.

Sin embargo, no es realmente sencillo acceder a una columna por su nombre porque DBMS_SQL El paquete usa posicionamiento y en una consulta dinámica es posible que no sepamos el orden de las columnas antes de la ejecución.

Además, en el contexto de esta pregunta, parece que es posible que no sepamos qué columna queremos mostrar en tiempo de compilación, supondremos que la columna que queremos mostrar se proporciona como un parámetro.

Podemos usar DBMS_SQL.describe_columns para analizar las columnas de un SELECT consulta después de que se haya analizado para crear una asignación dinámica de las columnas. Asumiremos que todas las columnas se pueden convertir en VARCHAR2 ya que queremos mostrarlos con DBMS_OUTPUT .

He aquí un ejemplo:

SQL> CREATE OR REPLACE PROCEDURE display_query_column(p_query VARCHAR2,
  2                                                   p_column VARCHAR2) IS
  3     l_cursor            INTEGER;
  4     l_dummy             NUMBER;
  5     l_description_table dbms_sql.desc_tab3;
  6     TYPE column_map_type IS TABLE OF NUMBER INDEX BY VARCHAR2(32767);
  7     l_mapping_table column_map_type;
  8     l_column_value  VARCHAR2(4000);
  9  BEGIN
 10     l_cursor := dbms_sql.open_cursor;
 11     dbms_sql.parse(l_cursor, p_query, dbms_sql.native);
 12     -- we build the column mapping
 13     dbms_sql.describe_columns3(l_cursor, l_dummy, l_description_table);
 14     FOR i IN 1 .. l_description_table.count LOOP
 15        l_mapping_table(l_description_table(i).col_name) := i;
 16        dbms_sql.define_column(l_cursor, i, l_column_value, 4000);
 17     END LOOP;
 18     -- main execution loop
 19     l_dummy := dbms_sql.execute(l_cursor);
 20     LOOP
 21        EXIT WHEN dbms_sql.fetch_rows(l_cursor) <= 0;
 22        dbms_sql.column_value(l_cursor, l_mapping_table(p_column), l_column_value);
 23        dbms_output.put_line(l_column_value);
 24     END LOOP;
 25     dbms_sql.close_cursor(l_cursor);
 26  END;
 27  /

Procedure created

Podemos llamar a este procedimiento con una consulta conocida solo en tiempo de ejecución:

SQL> set serveroutput on
SQL> exec display_query_column('SELECT * FROM scott.emp WHERE rownum < 5', 'ENAME');
SMITH
ALLEN
WARD
JONES

PL/SQL procedure successfully completed

SQL> exec display_query_column('SELECT * FROM scott.emp WHERE rownum < 5', 'EMPNO');
7369
7499
7521
7566

PL/SQL procedure successfully completed

Tenga cuidado con SQL dinámico:tiene los mismos privilegios que el usuario y, por lo tanto, puede ejecutar cualquier DML y DDL instrucción permitida para este esquema.

Por ejemplo, el procedimiento anterior podría usarse para crear o eliminar una tabla:

SQL> exec display_query_column('CREATE TABLE foo(id number)', '');
begin display_query_column('CREATE TABLE foo(id number)', ''); end;
ORA-01003: aucune instruction analysée
ORA-06512: à "SYS.DBMS_SQL", ligne 1998
ORA-06512: à "APPS.DISPLAY_QUERY_COLUMN", ligne 13
ORA-06512: à ligne 1

SQL> desc foo
Name Type   Nullable Default Comments 
---- ------ -------- ------- -------- 
ID   NUMBER Y