繁体   English   中英

列的 PostgreSQL 级联(不是外键)

[英]PostgreSQL Cascade for columns (not foreign key)

create table parent (
    child_type not null  
    child_id not null
);
create table child1(id not null);
create table child2(id not null);
create table child3(id not null);

父表中有一些行是这样的:

child_type,child_id
"child1",1
"child1",2
"child2",1
"child3",1

我想在删除父行时删除子行。 有没有办法在删除级联上触发这个触发器?

我认为(child_type,child_id)parent的主键(并且此建议仅在如下情况下才有效:如果您想删除父行以通过 FK 级联触发子行中的删除,则父级必须具有一个主键)

您可以像这样创建关联:

create table child1(
  child_type VARCHAR(20) DEFAULT 'child1', 
  id INT not null
  FOREIGN KEY (child_type,id) REFERENCES parent(child_type, child_id) ON DELETE CASCADE
);
create table child2(
  child_type VARCHAR(20) DEFAULT 'child2', 
  id INT not null
  FOREIGN KEY (child_type,id) REFERENCES parent(child_type, child_id) ON DELETE CASCADE
);
create table child3(
  child_type VARCHAR(20) DEFAULT 'child3', 
  id INT not null
  FOREIGN KEY (child_type,id) REFERENCES parent(child_type, child_id) ON DELETE CASCADE
);

您不能在父级复合 PK 的子级引用部分中只有id 子级必须具有与父级 PK 具有相同值的相同 N 列


FWIW 那个表结构真的很奇怪,它可能会一次又一次地咬你。

更喜欢更正常的东西,例如:

create table parent (
    id PRIMARY KEY
);
create table child1(id PRIMARY KEY, parent_id REFERENCES parent(id));
create table child2(id PRIMARY KEY, parent_id REFERENCES parent(id));
create table child3(id PRIMARY KEY, parent_id REFERENCES parent(id));

我希望这对您的实际问题来说是一个人为的情况,因为它确实是一个糟糕的设计。 假设您实际上“想要在我删除父行时删除子行” 除非您更改数据模型并定义 FK 约束,否则您需要在父表上使用删除触发器。 你不能在没有 FK 的情况下级联删除,因为这是你定义 Postgres 的地方。 顺便说一句,您的表定义无效。 Not Null 是约束不是数据类型,你还没有建立数据类型。 更正后,如果您的 child_type 列被理解为实际命名子表所在的表,您可以构建一个触发器,从相应的子表中删除相应的行。 一个非常糟糕的设计导致一个极其危险的假设,但是:

-- setup

    create table parent (
        child_type text    not null  
       ,child_id   integer not null
    );
    create table child1(id integer not null);
    create table child2(id integer not null);
    create table child3(id integer not null)

    insert into parent(child_type, child_id) 
      values ('child1',1),('child1',2),('child2',1),('child3',1);

    insert into child1(id) values (1),(2);
    insert into child2(id) values (1);
    insert into child3(id) values (1);

现在创建触发器函数,然后“附加”到父表。触发器函数现在构建并动态执行适当的删除语句。 注意我总是在执行之前生成一个提升通知来显示实际语句,并在此处执行此操作。 你可以认为没有必要。

-- build trigger function.
create or replace function parent_adr()
returns trigger 
language plpgsql
as $$
declare 
   base_del_lk constant text = 'delete from %s where id = %s'; 
   sql_delete_stmt_l text; 
begin
   sql_delete_stmt_l = format(base_del_lk,old.child_type, old.child_id);
   raise notice 'Running statement==%', sql_delete_stmt_l;
   EXECUTE  sql_delete_stmt_l;
   return old;
end; 
$$;

-- and define the trigger on the parent table.  
create trigger parent_adr_trig
    after delete
    on parent
    for each row
    execute procedure parent_adr(); 



--- test.     
delete from parent where child_type = 'child1';

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM