[英]Oracle delete rows in multiple tables based on single primary key.
大约有20个表基于单个主键-EmployeeId进行分支。 我想从数据库中完全淘汰掉大约12,000名员工。 当我删除员工时,其他进程更新这些员工的机会几乎为零。 我打算批量删除它们,然后提交。 从理论上讲,所有删除操作都不应该失败,但是我不确定是否要走光标路线,每500行提交一次还是什么。 这是现在的样子。
--STEP 1: Collect the EmployeeIds to delete in a temp table
Create table temp as select EmployeeId from Employee where <all conditions are met>;
--STEP 2: Delete names
Delete from EmployeeName where EmployeeId in (select EmployeeId from temp);
--STEP 3 - STEP 30: Delete all other child tables
Delete from table inner join another_table on some_key inner join yet_another_table on some_key where EmployeeId in (select EmployeeId from temp);
--STEP 4: Commit
commit;
如果您知道删除过程中遇到的任何麻烦,并且仍然想在没有光标的情况下执行整个操作,则可以使用DML错误记录 :
在某些情况下,最明显的解决方案是DML语句(INSERT ... SELECT,UPDATE,DELETE),但是由于DML对异常的反应方式,您可以选择避免DML。
默认情况下,当DML语句失败时,将回退整个语句,而不管检测到错误之前成功处理了多少行。
过去,解决此问题的唯一方法是单独处理每一行,最好使用FORALL和SAVE EXCEPTIONS子句进行批量操作。 在Oracle 10g数据库第2版中,引入了DML错误日志记录功能来解决此问题。 在大多数INSERT,UPDATE,MERGE和DELETE语句上添加适当的LOG ERRORS子句,无论错误如何,操作都能完成。
BEGIN
DBMS_ERRLOG.create_error_log (dml_table_name => 'EmployeeName');
END;
/
Delete from EmployeeName
where EmployeeId in (select EmployeeId from temp)
LOG ERRORS INTO err$_EmployeeName ('DELETE') REJECT LIMIT UNLIMITED;
假设您要维护数据的完整性,并且从一个表中删除时出错,那么您想要ROLLBACK
该员工的所有删除,则可以执行以下操作:
DECLARE
TYPE Emp_ID_Tab_Type IS TABLE OF Employee.EmployeeID%TYPE;
All_Employees Emp_ID_Tab_Type;
Deleted_Employees Emp_ID_Tab_Type := Emp_ID_Tab_Type();
Error_Employees Emp_ID_Tab_Type := Emp_ID_Tab_Type();
BEGIN
SELECT EmployeeID
BULK COLLECT INTO All_Employees
FROM Employees
WHERE 1 = 0; -- Your conditions
FOR i IN 1 .. All_Employees.COUNT LOOP
BEGIN
DELETE FROM child_table1
WHERE EmployeeID = All_Employees(i);
DELETE FROM child_table2
WHERE EmployeeID = All_Employees(i);
-- ...
DELETE FROM child_table20
WHERE EmployeeID = All_Employees(i);
DELETE FROM Employees
WHERE EmployeeID = All_Employees(i);
COMMIT;
Deleted_Employees.EXTEND;
Deleted_Employees(Deleted_Employees.COUNT) := All_Employees(i);
DBMS_OUTPUT.PUT_LINE( All_Employees(i) || ' deleted' );
EXCEPTION
WHEN others THEN
ROLLBACK;
Error_Employees.EXTEND;
Error_Employees(Error_Employees.COUNT) := All_Employees(i);
DBMS_OUTPUT.PUT_LINE( All_Employees(i) || ' error - ' || SQLERRM );
END;
END LOOP;
-- Do something with the errors
END;
在每个循环结束时使用COMMIT
并不是最快的方法,但可以确保您可以ROLLBACK
每个员工。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.