Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Greifen Sie dynamisch über den Spaltennamen auf den Cursor zu

Sie können das Paket DBMS_SQL verwenden um Cursor mit dynamischen Abfragen zu erstellen und darauf zuzugreifen.

Es ist jedoch nicht wirklich einfach, über den Namen auf eine Spalte zuzugreifen, da die Datei DBMS_SQL Das Paket verwendet die Positionierung und in einer dynamischen Abfrage kennen wir möglicherweise die Reihenfolge der Spalten vor der Ausführung nicht.

Darüber hinaus scheint es im Zusammenhang mit dieser Frage, dass wir möglicherweise nicht wissen, welche Spalte wir zur Kompilierzeit anzeigen möchten. Wir gehen davon aus, dass die Spalte, die wir anzeigen möchten, als Parameter angegeben wird.

Wir können DBMS_SQL.describe_columns verwenden um die Spalten eines SELECT zu analysieren Abfrage, nachdem sie analysiert wurde, um eine dynamische Zuordnung der Spalten zu erstellen. Wir gehen davon aus, dass alle Spalten in VARCHAR2 umgewandelt werden können da wir sie mit DBMS_OUTPUT anzeigen wollen .

Hier ist ein Beispiel:

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

Wir können diese Prozedur mit einer Abfrage aufrufen, die nur zur Laufzeit bekannt ist:

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

Seien Sie vorsichtig mit dynamischem SQL:Es hat die gleichen Rechte wie der Benutzer und kann daher jede DML und DDL ausführen -Anweisung für dieses Schema zulässig.

Das obige Verfahren könnte beispielsweise verwendet werden, um eine Tabelle zu erstellen oder zu löschen:

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