我们有两张桌子:
HUSBANDS
---------------
id
name
surname
age
WIFES
---------------
id
name
surname
age
husbandId --(with constrain -> HUSBANDS.ID)
并且假设我们需要编写删除60岁以上妻子及其丈夫的程序;)
使用典型的SQL语句执行此操作可能是完美的,但在Oracle中不可能从一个DELETE语句中的两个表中删除行,对吧?所以......
我们不能这样做:
PROCEDURE remove_old_wifes() IS
BEGIN
DELETE FROM husbands WHERE id IN (SELECT husbandId FROM wifes WHERE age >= 60);
DELETE FROM wifes WHERE age >= 60;
END;
因为约束。
另一方面,下面提到的解决方案也是错误的:
PROCEDURE remove_old_wifes() IS
BEGIN
DELETE FROM wifes WHERE age >= 60;
DELETE FROM husbands WHERE id IN (SELECT husbandId FROM wifes WHERE age >= 60);
END;
因为当我们首先移除妻子时,所有丈夫都不会被移除......
这种情况的典型解决方案是什么?
重要提示:我无法设置级联。
答案 0 :(得分:2)
你可以先用一个没有妻子的指示来更新丈夫。对于您的数据,我们使用age = -1
。然后从妻子[原文如此]中删除,然后从丈夫那里删除。
update husbands
set age = -1
where id in (select husbandId from wifes where age >= 60);
delete from wifes where age >= 60;
delete from husbands where age = -1;
答案 1 :(得分:0)
如果桌子上不允许“未婚丈夫”,你可以先拆除妻子,然后再拆除所有不再有妻子的丈夫。如果临时不一致是一个问题,您可能希望将删除包装在事务中。
PROCEDURE remove_old_wifes() IS
BEGIN
DELETE FROM wifes WHERE age >= 60;
DELETE FROM husbands WHERE id NOT IN (SELECT husbandId FROM wifes);
END;
答案 2 :(得分:0)
Oracle中有许多外键子句。 例如,您可以使用"删除级联"你的外键中的子句:
alter table WIFES
add foreign key (husbandId )
references HUSBANDS(id)
on delete cascade;
使用此子句,您可以删除两个表的行,只删除一个。 所以你的程序将是:
PROCEDURE remove_old_wifes() IS
BEGIN
DELETE FROM husbands WHERE id IN (SELECT husbandId FROM wifes WHERE age >= 60);
END;
如果您无法设置on delete delete cascade子句,则应使用全局临时表,例如:
create table gtt_id( id number) on commit delete rows;
PROCEDURE remove_old_wifes() IS
BEGIN
insert into gtt_id SELECT husbandId FROM wifes WHERE age >= 60;
delete FROM wifes WHERE age >= 60
DELETE FROM husbands WHERE id IN (SELECT id FROM gtt_id);
END;