简单介绍一下,我的数据库当中每个表都有RCD_STATUS字段,0是正常纪录,1是历史纪录;2是被删除的纪录,也就是我的数据库是从来不做更新和删除的,只做新增,这样我能显示一条记录从生到死的全过程,具体的细节还有很多,大家不用深究。第一个是调用的存储过程。第二个是执行的。我的目的是把同一组的纪录(我能找出来)除了操作员和时间不同,其他内容都相同的历史纪录删除。
create or replace procedure Del_Unwanted_His_Row is
--删除所有除了rcd_oper;rcd_time;id;rcd_status之外全部数据都一致的历史纪录
-- ZHENLI20011218
type typeCursor is ref cursor;
cursorTables typeCursor; --表游标
strTableName VARCHAR2(50); --当前表名
strSql varchar2(6000); --sql语句
strUserID varchar2(20); --当前用户
BEGIN
--SAVEPOINT A;
strUserID:='NJYYTEMP'; --USER名字为大写;
--取得指向所有符合条件的表的游标,通过判断表中是否有rcd_status来判断是否是历史表结构
open cursorTables for 'SELECT TABLE_NAME from ALL_TAB_COLUMNS where OWNER ='''||strUserID||''' AND COLUMN_NAME=''RCD_STATUS'' ORDER BY TABLE_NAME';
LOOP
FETCH cursorTables INTO strTableName;
EXIT WHEN cursorTables%NOTFOUND;
DEL_UNWANTED_HIS_ROW_FOR_TABLE(strUserID,strTableName);
END LOOP;
CLOSE cursorTables;
end Del_Unwanted_His_Row;
create or replace procedure DEL_UNWANTED_HIS_ROW_FOR_TABLE(strUserID IN VARCHAR2,strTableName in varchar2) is
type typeCursor is ref cursor;
cursorTables typeCursor; --表游标
cursorColumns typeCursor; --列游标
strColumnName varchar2(50); --当前列名
strSql varchar2(6000); --sql语句
intRowNum integer; --结果级行数
strWhereClause varchar2(6000); --删除操作时候的where语句
begin
--表中至少有两条历史纪录才进行后续操作
strSql:='select count(*) from '||strTableName||' where rcd_status=1';
execute immediate strSql into intRowNum;
if intRowNum >1 then
dbms_output.put_line(strTableName);
--为当前表删除多余的历史纪录
--取得当前表的所有列,
--除去了rcd_status;rcd_time;id三个字段,也就是说它们可以不同
open cursorColumns for 'SELECT COLUMN_NAME from ALL_TAB_COLUMNS where OWNER ='''||strUserID||''' AND TABLE_NAME='''||strTableName||''' AND COLUMN_NAME <>''RCD_STATUS'' AND COLUMN_NAME<>''RCD_TIME'' AND COLUMN_NAME<>''ID''';
--拼凑rcd_status不是2并且所有列相等的where条件字符串
--注意对null的处理不能用nvl(,0),日期类型会报错
strWhereClause:='where b.RCD_STATUS<>2 ';
loop
FETCH cursorColumns INTO strColumnName;
EXIT WHEN cursorColumns%NOTFOUND;
--拼凑where语句
strWhereClause:=strWhereClause||' AND (a.'||strColumnName||'=b.'||strColumnName||' or (a.'||strColumnName||' is null and b.'||strColumnName||' is null))';
end loop;
--删除多余的历史纪录
--即删除所有列都相等并且rcd_status=1的列当中不是第一个rowid的纪录
strSql:= 'DELETE FROM '||strTableName||' a WHERE a.RCD_STATUS=1 AND a.rowid <>(select min(rowid) from '||strTableName||' b '||strWhereClause||')';
-- disp_long_string(strsql); --显示长字符串,另见存储过程
execute immediate strSql;
commit;
CLOSE cursorColumns;
end if;
end DEL_UNWANTED_HIS_ROW_FOR_TABLE;