如何在Oracle PL/SQL中选择嵌套类型?
如何在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\'类型错误。
在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,无论是否使用并行查询。当然,很少有必要采取这么复杂的方法。
总之,选择哪种方法取决于数据集的大小和性能需求。对于大数据集,更倾向于使用全局临时表。但无论采用哪种方法,都需要考虑到多线程和特定需求的限制。
在 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!
谢谢,我会查看文档的。
: 我已编辑答案,请查看。希望对你有用。