从约束相关的两个表中删除行

时间:2014-05-03 17:40:47

标签: sql oracle plsql

我们有两张桌子:

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;

因为当我们首先移除妻子时,所有丈夫都不会被移除......

这种情况的典型解决方案是什么?

重要提示:我无法设置级联。

3 个答案:

答案 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;