我希望能够通过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;
如果我尝试,我会收到以下错误:
Line: 117 Column: 25 Type: error Text: PLS-00597: expression 'LT_RECS' in the INTO list is of wrong type
答案 0 :(得分:2)
11gR2之前的Oracle版本限制我们将BULK COLLECT用于记录的集合(嵌套表或varray)。在Oracle Docs上阅读更多here。
如果您想了解如何在11gR2中完成,请向下滚动到此答案的 EDIT 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;
我没有删除程序中的许多行,以便让您了解更改。
编辑:请参阅我上面提到的Oracle Docs链接中的“BULK COLLECT限制”部分以及here。
编辑#2:
您必须使用CREATE TYPE ... IS OBJECT
代替RECORD
。此外,您需要按照我尝试时的方式修改SELECT
语句。请参阅Oracle文档here和StackOverflow问题here以供进一步参考。
我在我的机器上运行的代码(运行Oracle 11g R2)如下:
- SELECT * FROM user_objects WHERE object_type ='TYPE'; 清晰的屏幕; 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!
答案 1 :(得分:1)
你在11gR2中尝试的是什么 - 你在哪个版本?
你帖子中唯一看错的是:
OPEN lc_date FOR
SELECT rowid, a.*
FROM table_name;
应该是这个......
OPEN lc_data FOR
SELECT a.rowid, a.*
FROM table_name a;
...但这些可能只是在您清理代码以便在此处发布时引入的错别字。
答案 2 :(得分:1)
我不认为我会采用这种方法,说实话。
更快的方法是执行多表插入:
然后使用DELETE对原始表执行删除.. WHERE ROWID IN(从MY_GLOBAL_TEMP_TAB中选择ORIGINAL_ROWID)
...然后提交。
我认为更快,更少的代码。