如何在Oracle PL/SQL中选择嵌套类型?

12 浏览
0 Comments

如何在Oracle PL/SQL中选择嵌套类型?

我希望能够通过rowid删除数据,然后立即将被删除的数据插入到审计表中。\n由于记录太多,无法使用\"INSERT INTO ... SELECT CRITERIA\"然后\"DELETE ... CRITERIA\"的方式。\n我已经知道如何仅使用rowid和\"INSERT INTO ... SELECT\"完成所有操作。\n在包体内部:\nsome_type类型是一个记录类型,包括row_id和full_row(table_name的ROWTYPE)。\nsome_type_list类型是一个索引为BINARY_INTEGER的记录列表。\ndo_stuff过程中:\nlc_data是一个SYS_REFCURSOR类型的游标。\nlt_recs是some_type_list类型的变量。\n开始部分:\n打开lc_data游标,选择rowid和a.*从table_name中。\n循环部分:\n将lc_data游标的结果集批量收集到lt_recs列表中,每次最多收集50000条记录。\n当lt_recs列表为空时退出循环。\n循环遍历lt_recs列表:\n使用rowid删除table_name中ROWID等于lt_recs(i).row_id的记录。\n使用\"INSERT INTO table_name_audit VALUES lt_recs(i).full_row\"将lt_recs(i).full_row插入到table_name_audit中。\n如果尝试以上操作,会出现以下错误:\n第117行第25列,类型为错误,错误信息为:PLS-00597: INTO列表中的表达式\'LT_RECS\'类型错误。

0
0 Comments

问题原因:

根据对问题描述的分析,问题出现的原因可能是代码中的一个错误。具体来说,SELECT语句中的FROM子句和SELECT子句中的列名之间的顺序不一致。

解决方法:

要解决这个问题,需要将SELECT语句中的FROM子句和SELECT子句中的列名顺序调整一致。

以下是修正后的代码示例:

OPEN lc_data FOR
  SELECT a.rowid, a.*
  FROM   table_name a;

这样修改后,问题应该得到解决。

0
0 Comments

在Oracle PL/SQL中,如何选择嵌套类型?

在处理大数据集时,有时需要选择嵌套类型。然而,使用临时表的方法在大数据集上性能不佳。因此,需要寻找一种更高效的方法。

一种更快的方法是执行多表插入操作:

1. 将表的列插入到审计表中,可能使用直接路径(APPEND提示)以提高效率。

2. 将行ID插入到一个在提交时删除行的全局临时表中。

然后,在原始表中执行一个删除操作,使用DELETE .. WHERE ROWID IN (SELECT ORIGINAL_ROWID FROM MY_GLOBAL_TEMP_TAB) ... 然后提交。

这种方法更快,代码更少。当然,使用截断或删除分区会更好,但SQL总是优于PL/SQL。

然而,在实践中,并不总是如此。特别是当考虑到多线程时,多线程同样适用于SQL和PL/SQL,无论是否使用并行查询。当然,很少有必要采取这么复杂的方法。

总之,选择哪种方法取决于数据集的大小和性能需求。对于大数据集,更倾向于使用全局临时表。但无论采用哪种方法,都需要考虑到多线程和特定需求的限制。

0
0 Comments

在 Oracle 11gR2 之前的版本中,我们受限于只能将 BULK COLLECT 用于记录的集合(嵌套表或VARRAY)。如果要了解在 11gR2 中如何使用,请参考此答案的 EDIT 2 部分。另一种选择可以是为每一列使用单独的集合,这种方法是最常用的。你可以创建以下类型的集合:

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;
   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;

在这个程序中,我没有删除很多行,以便让你理解这些更改。

EDIT : 请参考我之前给出的 Oracle 文档链接中的 "Restrictions on BULK COLLECT" 部分以及这里


EDIT #2 :


你需要使用 CREATE TYPE ... IS OBJECT 代替 RECORD。同时,你需要修改 SELECT 语句,就像我在尝试时所做的那样。请参考 Oracle 文档 这里 和 StackOverflow 的问题 这里 以供参考。

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

-- SELECT * FROM user_objects WHERE object_type = 'TYPE';
    CLEAR SCREEN;
    SET SERVEROUTPUT ON;
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;
/

** 输出 **:

TYPE temp_t_test compiled
TYPE temp_tbl_test compiled
anonymous block completed
Bulk Collect Successful!

谢谢,我会查看文档的。

: 我已编辑答案,请查看。希望对你有用。

0