Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Acessar o cursor pelo nome da coluna dinamicamente


Você pode usar o pacote DBMS_SQL para criar e acessar cursores com consultas dinâmicas.

No entanto, não é muito simples acessar uma coluna pelo nome porque o DBMS_SQL pacote usa posicionamento e em uma consulta dinâmica podemos não saber a ordem das colunas antes da execução.

Além disso, no contexto desta questão, parece que podemos não saber qual coluna queremos exibir em tempo de compilação, vamos supor que a coluna que queremos exibir é fornecida como parâmetro.

Podemos usar DBMS_SQL.describe_columns para analisar as colunas de um SELECT após ter sido analisada para construir um mapeamento dinâmico das colunas. Assumiremos que todas as colunas podem ser convertidas em VARCHAR2 já que queremos exibi-los com DBMS_OUTPUT .

Aqui está um exemplo:
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 chamar esse procedimento com uma consulta conhecida apenas em tempo de execução:
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

Tenha cuidado com SQL dinâmico:ele tem os mesmos privilégios que o usuário e, portanto, pode executar qualquer DML e DDL instrução permitida para este esquema.

Por exemplo, o procedimento acima pode ser usado para criar ou descartar uma tabela:
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