Plsql 具有动态列名的存储过程

Plsql 具有动态列名的存储过程,plsql,oracle11g,Plsql,Oracle11g,我正在尝试打印我们不知道列名的多表行。我从一天开始就在尝试这一点,我想出了这个错误的程序“必须声明emp\u dummy\u col”。请帮帮我。 多谢各位 create or replace procedure sp_display as CURSOR cur_emp is select EMP_ID,EMP_NAME,DEPT_IT,DOJ,LOCATION from employee; emp_rows cur_emp%rowtype; type emp_table is

我正在尝试打印我们不知道列名的多表行。我从一天开始就在尝试这一点,我想出了这个错误的程序“必须声明emp\u dummy\u col”。请帮帮我。 多谢各位

create or replace procedure sp_display
as
   CURSOR cur_emp is select EMP_ID,EMP_NAME,DEPT_IT,DOJ,LOCATION from employee;
   emp_rows cur_emp%rowtype;
   type emp_table is table of emp_rows%type;
   emp_dummy_table emp_table;
   CURSOR cur_col is select column_name from user_tab_cols where table_name ='EMPLOYEE';
   emp_row cur_col%rowtype;
   type emp_table1 is table of emp_row%type;
   emp_dummy_col emp_table1;
begin
   open cur_emp;
      fetch cur_emp bulk collect into emp_dummy_table;
   close cur_emp;
   open cur_col;
      fetch cur_col bulk COLLECT into emp_dummy_col; 
   close cur_col;
   for i in 1..emp_dummy_table.count
   loop
      for j in 1..emp_dummy_col.count
      loop
         DBMS_OUTPUT.PUT_LINE(emp_dummy_table(i).emp_dummy_col(j));
      end loop;
   end loop;
end;

正如Justin Cave所提到的,您可以使用包DBMS_SQL进行大量工作

下面只是一个简单的例子

SET SERVEROUTPUT ON
SET FEEDBACK OFF
CLEAR

DECLARE
  -- The SQL Statement
  V_SQL VARCHAR2(4000) := 'select EMP_ID,EMP_NAME,DEPT_IT,DOJ,LOCATION from employee';
  -- The cursor (number) variable
  V_CURSOR INTEGER;
  -- Variable to hold the return value of DBMS_SQL.EXECUTE (Number of processed rows)
  V_NUM_ROWS NUMBER;
  -- Variable to hold the return value of DBMS_SQL.DESCRIBE_COLUMNS
  V_COL_CNT INTEGER;
  -- Column description table. Outcome from DBMS_SQL.DESCRIBE_COLUMNS
  V_DESC DBMS_SQL.DESC_TAB;
  -- Variable for the current column number when iterating over the column description collection
  V_COL_NUM NUMBER;
  -- (generic) Variable for a VARCHAR2-Column
  V_VARC_COL VARCHAR2(4000);
  -- (generic) Variable for a NUMBER-Column
  V_NUM_COL NUMBER;
BEGIN

  -- Open a cursor
  V_CURSOR := DBMS_SQL.OPEN_CURSOR;
  -- Parse the SQL-Query (without any bindings etc.)
  DBMS_SQL.PARSE(V_CURSOR, V_SQL, DBMS_SQL.NATIVE);

  -- Execute the parsed query and return the number of processed rows. 
  -- May be 0 or undefined on SELECT- and DDL-Statements and should be ignored
  V_NUM_ROWS := DBMS_SQL.EXECUTE(V_CURSOR);

  -- Get the columns description table
  DBMS_SQL.DESCRIBE_COLUMNS(V_CURSOR, V_COL_CNT, V_DESC);

  V_COL_NUM := V_DESC.FIRST;

  IF (V_COL_NUM IS NOT NULL) THEN
    LOOP
      -- Assign variables to column types
      CASE V_DESC(V_COL_NUM).COL_TYPE
        WHEN DBMS_SQL.NUMBER_TYPE THEN
          DBMS_SQL.DEFINE_COLUMN(V_CURSOR, V_COL_NUM, V_NUM_COL);
        WHEN DBMS_SQL.VARCHAR2_TYPE THEN
          DBMS_SQL.DEFINE_COLUMN(V_CURSOR, V_COL_NUM, V_VARC_COL, 4000);
          -- more branches if other column types are expected/supported (Date, LOBs etc.)
        ELSE
          NULL;
      END CASE;
      V_COL_NUM := V_DESC.NEXT(V_COL_NUM);
      EXIT WHEN(V_COL_NUM IS NULL);
    END LOOP;

    -- Fetch the rows
    V_NUM_ROWS := DBMS_SQL.FETCH_ROWS(V_CURSOR);
    IF (V_NUM_ROWS > 0) THEN
      LOOP
        -- Column handling
        FOR L_I IN V_DESC.FIRST .. V_DESC.LAST LOOP
          CASE V_DESC(L_I).COL_TYPE
          -- NUMBER column type value handler
            WHEN DBMS_SQL.NUMBER_TYPE THEN
              DBMS_SQL.COLUMN_VALUE(V_CURSOR, L_I, V_NUM_COL);
              V_VARC_COL := TO_CHAR(V_NUM_COL);
              -- VARCHAR2 column type value handler
            WHEN DBMS_SQL.VARCHAR2_TYPE THEN
              DBMS_SQL.COLUMN_VALUE(V_CURSOR, L_I, V_VARC_COL);
              -- more branches if other column types are expected/supported (Date, LOBs etc.)
            ELSE
              --Handling for unsupported column types (if necessary)
              NULL;
          END CASE;
          DBMS_OUTPUT.PUT(V_DESC(L_I).COL_NAME || '" = "' || V_VARC_COL || '"');
          IF (L_I < V_DESC.COUNT) THEN
            DBMS_OUTPUT.PUT('  |  ');
          END IF;
        END LOOP;
        DBMS_OUTPUT.PUT_LINE('');
        -- Fetch the next row
        V_NUM_ROWS := DBMS_SQL.FETCH_ROWS(V_CURSOR);
        -- Exit loop if no more row is fetched
        EXIT WHEN V_NUM_ROWS = 0;
      END LOOP;
    END IF;
  END IF;
  -- Close the cursor (important!)
  DBMS_SQL.CLOSE_CURSOR(V_CURSOR);

EXCEPTION
  WHEN OTHERS THEN
    -- Close the cursor (important!) if any error occurs
    IF (DBMS_SQL.IS_OPEN(V_CURSOR)) THEN
      DBMS_SQL.CLOSE_CURSOR(V_CURSOR);
    END IF;
    -- Rethrow the exception
    RAISE;
END;
/
有关DBMS_SQL的详细/进一步信息:

或 !!安全警告


这种动态SQL的使用容易受到SQL注入和其他技术的影响

Hm,您的代码示例并没有真正做到您所要求的。它希望您告诉列,请参阅:

从employee中选择EMP_ID、EMP_名称、IT部门、DOJ、地点

1您可以获得如下表中的未知列我在本例中使用的是表新闻

begin
    for rec in
           (select column_name from user_tab_cols
           where table_name='NEWS') loop
        dbms_output.put_line(rec.column_name);
    end loop;
end;
2如果要打印出数据,这在PLSQL中非常麻烦,请参阅

3如果你善于妥协,试试这种方法。我根据从用户选项卡中学习的字段构建了一个动态SQL语句。动态SQL将每列的字符串值连接到一行中,最后我在该行上获取一个游标

为了方便起见,我还收集header变量中的列名

declare
    statement varchar2(4000);
    header varchar2(4000);
    TYPE TCur IS REF CURSOR;
    cur TCur;
    TYPE TRec IS RECORD (
      line varchar2(4000)
    );
    rec TRec;
begin

    for rec in
           (select column_name from user_tab_cols
           where table_name='NEWS') loop
        if statement is not null then
            statement:=statement||'||'',''||';
            header:=header||',';
        end if;
        statement:=statement||rec.column_name;
        header:=header||rec.column_name;
    end loop;
    statement:='select '||statement||' as line from '||'NEWS';
    dbms_output.put_line(header);
    open cur for statement;
    loop
        fetch cur into rec;
        exit when cur%notfound;
        dbms_output.put_line(rec.line);
    end loop;
    close cur;
end;
例如:

NEWS_ID,NEWS
0,Some new PLSQL hack has been done
1,And the day is not over yet!

你到底想干什么?动态访问记录中的字段将是一件痛苦的事情——您必须在字符串变量中动态构建整个PL/SQL块。我的猜测是,无论您真正想要实现什么,使用动态SQL都比使用动态PL/SQL更容易,所以这是可能的。谢谢您知道主cur_emp查询中的列-您正在显式选择emp_ID和其他四个列。为什么不明确地提及它们呢?如果您没有选择其他列,这些列将包含在cur_col查询中,但emp_dummy_表中没有匹配字段,那么您希望这些列发生什么情况?我们真的不清楚为什么要这样做,而不仅仅是在SQL中查询表。好吧,你得到了一个点@Alex Poole,但不是选择我将放为*的特定列,如果我想更改表名呢?以上程序只是一个实验。