使用一个 SQL 脚本删除父子行

18

我希望通过一个语句同时删除子行和父行,而不是先删除子行再写另一个 SQL 语句来删除父行。我们使用的是 Oracle 数据库。

更新: 我没有 DELETE ON CASCADE 的权限。

7个回答

17

使用级联删除定义外键。然后,您只需要删除“父”行。


2
抱歉,我没有权限这样做。 - WowBow
4
@WowBow - 那么您需要两个“DELETE”语句。 - Lamak
@Lamak 取决于有多少子表,可能是两个或三十个。 - ryvantage

5

在一个比较大且极其关键的数据库中遇到这个问题的糟糕经历之后,我决定为它做一个银弹!因为我找不到其他办法!实际上,该主题中的解决方案/答案都无法满足问题的需求。

请查看我在Github上的CASCADELETE存储库。


非常好的脚本,但我没有权限这样做。 - Wendel
非常棒的脚本,看起来确实能够完成任务。恭喜! - Fede Garcia

4
delete from 
(
select * from parent join child using (id)
where id = 1
)

警告!仅在父行和子行均存在的情况下才会删除。不会删除没有子行的父行。


1
除非定义了级联删除,否则它不会删除“parent”。只需查看每种情况的“EXPLAIN PLAN”即可... - gavenkoa

2
你只能通过触发器来完成 - 也就是说,只能做得很糟糕。
create table parent
(pid number,
   constraint parent_pk
     primary key (pid)
     using index
);

create table child
  (cid number,
   pid number,
   constraint child_pk
     primary key(cid)
     using index,
   constraint child_fk
     foreign key (pid)
     references parent (pid)
  );

create index child_fk on child (pid);

create trigger fake_delete_cascade
before delete on parent
for each row
begin
  delete from child where pid = :old.pid;
end;
/

insert into parent values (1);
insert into child values (1,1);
commit;
select count(*) from child;
delete from parent where pid = 1;
select count(*) from child;

1
如果您希望在删除父行时始终删除子项,则可以声明外键约束,以便Oracle自动执行子项删除。
create table parent (
  parentID number primary key,
  parentData varchar2(100)
);

create table child (
  childID number primary key,
  parentID number references parent( parentID ) on delete cascade,
  childData varchar2(100)
);

例如,将声明一个父表和一个子表,并在删除父行时自动删除子行。如果您不希望自动执行此类强制操作,或者不喜欢在后台发生“自动幻觉”时添加复杂性,那么可能只能使用多个DELETE语句。

谢谢你的帮助。虽然我没有创建表或更改ON DELETE CASCADE的权限。该表已经有数千条记录。所以我执行了两个SQL语句。 - WowBow

0

另一种(乏味的)做法是,在删除之后(或之前)创建一个触发器,但我们在数据库中却无法使用外键约束。是的,你需要在触发器中编写另一个删除查询。

但是如果你不能添加删除级联,我不确定你是否能够添加触发器......


0
如果有人需要的话,我刚刚写了一个PLSQL脚本来处理表中所有外键约束,参考了this Stackoverflow question。希望能对你有所帮助。
DECLARE
  CURSOR constraint_cursor IS SELECT *
                              FROM (SELECT a.table_name,
                                           a.constraint_name,
                                           a.column_name,
                                           c_pk.table_name r_table_name,
                                           b.column_name   r_column_name
                                    FROM user_cons_columns a
                                           JOIN user_constraints c ON a.owner = c.owner
                                                                        AND a.constraint_name = c.constraint_name
                                           JOIN user_constraints c_pk ON c.r_owner = c_pk.owner
                                                                           AND
                                                                         c.r_constraint_name = c_pk.constraint_name
                                           JOIN user_cons_columns b ON C_PK.owner = b.owner
                                                                         AND
                                                                       C_PK.CONSTRAINT_NAME = b.constraint_name AND
                                                                       b.POSITION = a.POSITION
                                    WHERE c.constraint_type = 'R'
                                      and c_pk.owner = 'YOUR SCHEMA HERE') tbl;
  sql_statement VARCHAR2(2048) := NULL;
  tab_row       constraint_cursor%rowtype;
BEGIN
  OPEN constraint_cursor;
  FOR i in 1..80 LOOP
    FETCH constraint_cursor into tab_row;
    EXECUTE IMMEDIATE 'ALTER table ' || tab_row.table_name || ' drop constraint ' || tab_row.constraint_name;
    EXECUTE IMMEDIATE 'ALTER table ' || tab_row.table_name || ' add constraint ' || tab_row.constraint_name || ' FOREIGN KEY (' ||
    tab_row.column_name || ') references ' || tab_row.r_table_name || '(' || tab_row.r_column_name || ') ON DELETE CASCADE ';
  end loop;
  close constraint_cursor;
end;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接