oracle pl/sql中如何选择成嵌套类型?

Scr*_*Dev 5 oracle plsql oracle11g

我希望能够通过 rowid 删除,然后立即将要删除的数据插入审计表中。

有太多的记录到 INSERT INTO ... SELECT CRITERIA那时DELETE ... CRITERIA

我已经知道如何仅使用 rowid 和INSERT INTO ... SELECT.

内部包装体:

TYPE some_type IS RECORD (
   row_id    ROWID,
   full_row  table_name%ROWTYPE
);
TYPE some_type_list IS TABLE OF some_type
   INDEX BY BINARY_INTEGER;

PROCEDURE do_stuff
IS
   lc_data  SYS_REFCURSOR;
   lt_recs  some_type_list;
BEGIN
   OPEN lc_date FOR
      SELECT rowid, a.*
      FROM   table_name;
   LOOP
      FETCH lc_data
      BULK COLLECT INTO lt_recs
      LIMIT 50000;
      EXIT WHEN lt_recs.COUNT = 0;
      --
      FORALL i IN lt_recs.FIRST..lt_recs.LAST
         DELETE table_name
         WHERE  ROWID = lt_recs(i).row_id;
      --
      FORALL i IN lt_recs.FIRST..lt_recs.LAST
         INSERT INTO table_name_audit VALUES lt_recs(i).full_row;
   END LOOP;
END;
Run Code Online (Sandbox Code Playgroud)

如果我尝试,我会收到以下错误:

Line: 117 Column: 25 Type: error Text: PLS-00597: expression 'LT_RECS' in the INTO list is of wrong type

Rac*_*cha 3

11gR2 之前的 Oracle 版本限制我们在记录集合(嵌套表或 varray)中使用 BULK COLLECT。在 Oracle 文档上阅读更多内容。

如果您想了解 11gR2 中是如何完成的,请向下滚动到此答案的编辑 2部分。

另一种选择是为每列使用单独的集合 - 这是最广泛使用的方法。在此您可以拥有:

/*
TYPE some_type IS RECORD (
   row_id    ROWID,
   full_row  table_name%ROWTYPE
);
TYPE some_type_list IS TABLE OF some_type
   INDEX BY BINARY_INTEGER;
-- */
CREATE TYPE t_row_id IS TABLE OF ROWID;
CREATE TYPE t_col1 IS TABLE OF table_name.col1%TYPE;
CREATE TYPE t_col2 IS TABLE OF table_name.col2%TYPE;
CREATE TYPE t_col3 IS TABLE OF table_name.col3%TYPE;
...
...
CREATE TYPE t_colN IS TABLE OF table_name.colN%TYPE;

PROCEDURE do_stuff
IS
   lc_data  SYS_REFCURSOR;
   -- lt_recs  some_type_list;
   row_id t_row_id;
   col1 t_col1;
   col2 t_col2;
   col3 t_col3;
   ...
   ...
   colN t_colN;
BEGIN
   OPEN lc_date FOR
      SELECT rowid, a.*
      FROM   table_name;
   LOOP
      FETCH lc_data
      BULK COLLECT INTO row_id, col1, col2, col3, ..., colN
      LIMIT 50000;
      EXIT WHEN lt_recs.COUNT = 0;
      --
      FORALL i IN row_id.FIRST..row_id.LAST
         DELETE table_name
         WHERE  ROWID = row_id(i);
      --
      FORALL i IN col1.FIRST..col1.LAST
         INSERT INTO table_name_audit VALUES (col1(i), col2(i), col3(i), ..., colN(i));
   END LOOP;
END;
Run Code Online (Sandbox Code Playgroud)

为了让您了解这些更改,我没有删除程序中的许多行。

编辑:请参阅我在上面和此处给出的 Oracle 文档链接的“BULK COLLECT 的限制”部分。


编辑#2:


你必须使用CREATE TYPE ... IS OBJECT而不是RECORD. 另外,您需要按照SELECT我尝试时所做的方式修改该语句。请参阅此处的Oracle 文档和此处的StackOverflow 问题以获取进一步参考。

我在我的机器(运行Oracle 11g R2)上尝试的代码如下:

-- SELECT * FROM user_objects WHERE object_type = 'TYPE'; 清晰的屏幕;设置服务器输出打开;

CREATE OR REPLACE TYPE temp_t_test AS OBJECT ( -- << OBJECT, not RECORD.
  test_id  INTEGER
, test_val VARCHAR2(50)
);
/

CREATE OR REPLACE TYPE temp_tbl_test AS TABLE OF TEMP_T_TEST;
/

DECLARE
  v_test TEMP_TBL_TEST;
BEGIN
  SELECT temp_t_test(t_id, t_val) -- << Notice the syntax
  -- I'm selecting the columns as the defined OBJECT type.
  BULK COLLECT INTO v_test
    FROM (SELECT 1 AS t_id, 'ABCD' AS t_val FROM dual
          UNION ALL
          SELECT 2, 'WXYZ' FROM dual
          UNION ALL
          SELECT 3, 'PQRS' FROM dual);

  dbms_output.put_line('Bulk Collect Successful!');
END;
/
Run Code Online (Sandbox Code Playgroud)

** 输出 **:

TYPE temp_t_test compiled
TYPE temp_tbl_test compiled
anonymous block completed
Bulk Collect Successful!
Run Code Online (Sandbox Code Playgroud)