我有一个脚本,可以将满足特定条件的记录复制到临时表中。 然后原始表被截断,记录被复制回来。
用于创建临时表的语句是;
create table ARCHIVE_TMP as select * from ORIGINAL_TABLE where TIMESTAMP_UPDATED < '2017-10-04'
将记录再次复制回来的语句是;
insert /*+ APPEND */ into ORIGINAL_TABLE select * from ARCHIVE_TMP
当在脚本中执行第二行时,它会引发异常
ORA-01007: variable not in select list
,但如果我手动运行第二条语句,它会按预期工作。
我已检查用户是否具有 CREATE 和 INSERT 权限,因为之前存在问题,即权限被分配给角色而不是用户。
我还尝试在
select
语句中指定列名称,而不是使用 select *
但这没有帮助。
以下是整个脚本;
create or replace procedure TRUNCATE_EXPIRED_ARCHIVE_DATA
(
p_retention_period in number := 84,
)
as
begin
declare
cursor table_cursor is
select owner, table_name, column_name, data_type
from all_tab_columns
where table_name like '%!_A' escape '!'
and column_name like 'TIMESTAMP!_%' escape '!'
group by owner, table_name, column_name, data_type
order by table_name, column_name;
RetentionDt date := null;
ExpiredCount number := 0;
InsertedCount number := 0;
TableExists number := 0;
ExpiredSql varchar2(500);
SelectSql varchar2(800);
SqlStmt varchar2(1300);
begin
RetentionDt := add_months(sysdate, p_retention_period * -1);
for table_rec in table_cursor loop
begin
-- Check if there are any expired records...
SelectSql := 'select count(*) from ' || table_rec.owner || '.' || table_rec.table_name;
ExpiredSql := ' where ' || table_rec.column_name || ' < ''' || RetentionDt || '''';
SqlStmt := SelectSql || ExpiredSql;
execute immediate SqlStmt into ExpiredCount;
if (ExpiredCount > 0) then
-- Drop the temporary table if it already exists...
SelectSql := 'select count(*) from tab where tname = ''ARCHIVE_TMP''';
execute immediate SelectSql into TableExists;
if (TableExists > 0) then
SelectSql := 'drop table REODT_PROD.ARCHIVE_TMP';
execute immediate SelectSql;
end if;
-- Transfer the records to be retained to the temporary table...
SelectSql := 'create table REODT_PROD.ARCHIVE_TMP as select * from ' || table_rec.owner || '.' || table_rec.table_name || ' where ' || table_rec.column_name || ' >= ''' || to_char(RetentionDt, 'YYYY-MM-DD') || '''';
execute immediate SelectSql;
InsertedCount := sql%rowcount;
commit;
if (InsertedCount > 0) then
SelectSql := 'truncate table ' || table_rec.owner || '.' || table_rec.table_name;
dbms_output.put_line('Truncate Table : ' || SelectSql);
execute immediate SelectSql;
SelectSql := 'insert /*+ APPEND */ into ' || table_rec.owner || '.' || table_rec.table_name || ' select * from REODT_PROD.ARCHIVE_TMP';
execute immediate SelectSql into InsertedCount;
commit;
end if;
end if;
end;
end loop;
end;
end;
/
SelectSql := 'insert /*+ APPEND */ into ' || table_rec.owner || '.' || table_rec.table_name || ' select * from REODT_PROD.ARCHIVE_TMP';
execute immediate SelectSql into InsertedCount;
是一个
INSERT
(而不是 SELECT
),所以您不希望有 INTO
子句。
您可以将程序简化为:
create or replace procedure TRUNCATE_EXPIRED_ARCHIVE_DATA
(
p_retention_period in number := 84
)
as
TABLE_NOT_FOUND EXCEPTION;
RetentionDt date := add_months(TRUNC(sysdate), -p_retention_period);
ExpiredCount number := 0;
InsertedCount number := 0;
PRAGMA EXCEPTION_INIT(TABLE_NOT_FOUND, -942);
begin
for table_rec in (
select owner, table_name, column_name, data_type
from all_tab_columns
where table_name like '%!_A' escape '!'
and column_name like 'TIMESTAMP!_%' escape '!'
order by table_name, column_name
) loop
-- Check if there are any expired records...
execute immediate
'select count(*)'
|| ' from "' || table_rec.owner || '"."' || table_rec.table_name || '"'
|| ' where "' || table_rec.column_name || '" < :1'
INTO ExpiredCount
USING RetentionDt;
IF ExpiredCount = 0 THEN
DBMS_OUTPUT.PUT_LINE(
'"' || table_rec.owner || '"."' || table_rec.table_name || '" Not found'
);
CONTINUE;
END IF;
BEGIN
execute immediate 'drop table REODT_PROD.ARCHIVE_TMP';
EXCEPTION
WHEN TABLE_NOT_FOUND THEN
NULL;
END;
execute immediate
'create table REODT_PROD.ARCHIVE_TMP as'
|| ' select * from "' || table_rec.owner || '"."' || table_rec.table_name || '"'
|| ' where "' || table_rec.column_name || '"'
|| ' >= TIMESTAMP ''' || TO_CHAR(RetentionDt, 'YYYY-MM-DD HH24:MI:SS') || '''';
InsertedCount := sql%rowcount;
commit;
if InsertedCount > 0 then
execute immediate 'truncate table "' || table_rec.owner || '"."' || table_rec.table_name || '"';
execute immediate
'insert /*+ APPEND */ into "' || table_rec.owner || '"."' || table_rec.table_name || '"'
|| ' select * from REODT_PROD.ARCHIVE_TMP';
commit;
end if;
end loop;
end;
/