按列名称动态访问游标

no_*_*ord 3 oracle plsql cursor

我可以动态访问游标的列吗?我的意思是名字?这样的事情:

declare
 v_cursor := select * from emp;
begin
 FOR reg IN v_cursor LOOP
   dbms_output.put_line(**reg['column_name_as_string']**);
 end loop;
end;
Run Code Online (Sandbox Code Playgroud)

我知道粗体部分不是 PL/SQL,但我正在寻找类似的东西,无法在任何地方找到它.

谢谢!

Vin*_*rat 6

您可以使用该包DBMS_SQL创建和访问具有动态查询的游标.

但是,按名称访问列并不是非常简单,因为DBMS_SQL包使用定位,在动态查询中,我们可能在执行之前不知道列的顺序.

此外,在这个问题的上下文中,似乎我们可能不知道我们想要在编译时显示哪一列,我们将假设我们要显示的列作为参数给出.

我们可以使用它DBMS_SQL.describe_columns来分析SELECT查询后的列,以构建列的动态映射.我们将假设所有列都可以转换为,VARCHAR2因为我们想要显示它们DBMS_OUTPUT.

这是一个例子:

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
Run Code Online (Sandbox Code Playgroud)

我们可以使用仅在运行时知道的查询来调用此过程:

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
Run Code Online (Sandbox Code Playgroud)

请谨慎使用动态SQL:它具有与用户相同的权限,因此可以执行此架构允许的任何DML 和DDL语句.

例如,上述过程可用于创建或删除表:

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      
Run Code Online (Sandbox Code Playgroud)

  • 也许你可以添加两行示例.我的意思是,回答"RTFM"的问题不是示例驱动的方法,因为stackoverflow通过:)建立了它的声誉 (2认同)