Oracle
 sql >> Database >  >> RDS >> Oracle

Accedi al cursore in base al nome della colonna in modo dinamico

Puoi utilizzare il pacchetto DBMS_SQL per creare e accedere a cursori con query dinamiche.

Tuttavia non è molto semplice accedere a una colonna per nome perché DBMS_SQL il pacchetto utilizza il posizionamento e in una query dinamica potremmo non conoscere l'ordine delle colonne prima dell'esecuzione.

Inoltre, nel contesto di questa domanda, sembra che potremmo non sapere quale colonna vogliamo visualizzare in fase di compilazione, assumeremo che la colonna che vogliamo visualizzare sia data come parametro.

Possiamo usare DBMS_SQL.describe_columns per analizzare le colonne di un SELECT query dopo che è stata analizzata per creare una mappatura dinamica delle colonne. Assumeremo che tutte le colonne possano essere convertite in VARCHAR2 poiché vogliamo visualizzarli con DBMS_OUTPUT .

Ecco un esempio:

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

Possiamo chiamare questa procedura con una query nota solo in fase di esecuzione:

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

Prestare attenzione con SQL dinamico:ha gli stessi privilegi dell'utente e può quindi eseguire qualsiasi DML e DDL istruzione consentita per questo schema.

Ad esempio, la procedura precedente potrebbe essere utilizzata per creare o eliminare una tabella:

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