简体   繁体   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);

And there's some rows in table parent like this:父表中有一些行是这样的:

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

I want to delete child row when I delete parent row.我想在删除父行时删除子行。 Is there any way to make this trigger on delete cascade?有没有办法在删除级联上触发这个触发器?

I presume that (child_type,child_id) is the primary key of parent (and this advice will only work if it is thus: if you want deleting of a parent row to trigger a delete in a child via a FK cascade, the parent must have a primary key)我认为(child_type,child_id)parent的主键(并且此建议仅在如下情况下才有效:如果您想删除父行以通过 FK 级联触发子行中的删除,则父级必须具有一个主键)

You create associations like this:您可以像这样创建关联:

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
);

You can't have just id in the child references part of the composite PK in the parent;您不能在父级复合 PK 的子级引用部分中只有id child has to have the same N columns with the same values as the parent PK has子级必须具有与父级 PK 具有相同值的相同 N 列


FWIW that table structure is really wonky, and it will probably come around to bite you time and again. FWIW 那个表结构真的很奇怪,它可能会一次又一次地咬你。

Prefer something more normal, like:更喜欢更正常的东西,例如:

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));

I hope this is a contrived situation for you actual problem, as it really is a terrible design.我希望这对您的实际问题来说是一个人为的情况,因为它确实是一个糟糕的设计。 Assuming you actually "want to delete child row when I delete parent row" .假设您实际上“想要在我删除父行时删除子行” Unless you alter your data model and define FK constraints you require a delete trigger on table parent.除非您更改数据模型并定义 FK 约束,否则您需要在父表上使用删除触发器。 You CANNOT cascade deletes without FK as that is where you define to Postgres to do so.你不能在没有 FK 的情况下级联删除,因为这是你定义 Postgres 的地方。 BTW, your table definitions are invalid.顺便说一句,您的表定义无效。 Not Null is a constraint not a data type, you have not established a data type. Not Null 是约束不是数据类型,你还没有建立数据类型。 After correcting that you can build a trigger which deletes the corresponding rows from the appropriate child table if your child_type column is understood to actually name the table in which the child resides.更正后,如果您的 child_type 列被理解为实际命名子表所在的表,您可以构建一个触发器,从相应的子表中删除相应的行。 A very poor design leading to a extremely risky assumption, but:一个非常糟糕的设计导致一个极其危险的假设,但是:

-- 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);

Now create the trigger function then 'attach' to parent table' The trigger function now builds and dynamically executes the appropriate delete statement.现在创建触发器函数,然后“附加”到父表。触发器函数现在构建并动态执行适当的删除语句。 Note I always generate a raise notice to display the actual statement before executing it, and do so here.注意我总是在执行之前生成一个提升通知来显示实际语句,并在此处执行此操作。 You may consider it not necessary.你可以认为没有必要。

-- 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