Postgresql 如何在Postgres中使用外键和关系表删除子记录

Postgresql 如何在Postgres中使用外键和关系表删除子记录,postgresql,Postgresql,我有一个表设计,其中使用关系表处理各种实体的“注释”。 例如,存在以下表格 'notes' table having fields id and note 'knifes' table having as only field an id 'knife_notes' table having knife_id and note_id, being foreign keys to 'id' in knifes table and notes 'id' in notes table respect

我有一个表设计,其中使用关系表处理各种实体的“注释”。 例如,存在以下表格

'notes' table having fields id and note
'knifes' table having as only field an id
'knife_notes' table having knife_id and note_id, being foreign keys to 'id' in knifes table 
and notes 'id' in notes table respectively.
更新:刀注释表中的注释id字段是唯一的,因此每个注释只能与一个特定刀相关

为刀(父对象)添加注释(即子对象)时,将创建注释记录,并在表knife_notes中创建记录,从而关联注释id和刀id

这两个外键具有“On Delete Cascade”。 但是,删除刀时,只有刀_注释中的记录被“级联”删除,而不是注释表中的记录


在删除刀具时,我是否需要第二次查询来删除notes记录,或者是否有更好的方法?

您所做的是在刀具和notes之间创建n-to-m关系。你确定这就是你需要的吗

因为,按照现在设置数据模型的方式,不删除注释实际上是可取的。当前模型允许(除其他外):

一把有一个音符的刀

B.具有1个以上注释的特定刀(刀_注释中的2行指向同一刀和不同注释)

C.与多刀相关的特定注释

由于场景C,数据库不能从knive_notes表级联到notes表:可能还有其他表依赖于特定的notes

要使其可视化,请在knive_notes表中考虑以下场景:

id   knife_id    note_id
--------------------------------------
1    11          101
2    11          102
3    12          103
4    13          103
从数据库的角度来看,这是完全合法的;注103用于针织物12和13。现在,如果要删除knive 12,数据库不能简单地删除note 103,因为它仍然可以被其他刀具使用(事实上确实如此)

我可以想到两种解决方案: 1.简化数据模型 2.在PostgreSQL中创建触发器或规则

扩展选项:

  • 数据模型:
  • 为什么不创建一个只有

    • 编织
    • 注释(将外键设置为knive)
    这样,一个刀可以有多个音符,但一个音符始终与一个刀相关。但是,如果一个注释被多次使用或在多个角色中使用(例如,如果您还有一个表“guns”也需要注释,或者如果一个特定注释被knive表中的多行使用(“该knive的颜色为红色”),则这将不起作用

  • 触发或规则
  • 使用规则,您可以重写SQL查询。使用触发器,您可以在对表执行操作之前或之后执行函数。 查找&s

    我自己,我最习惯使用触发器。我基本上会创建一个on delete触发器来启动一个触发器函数。在该函数中,我会检查该便笺是否在其他地方使用,如果是这种情况,则对该便笺执行delete

    CREATE FUNCTION try_to_delete_note() RETURNS trigger AS ##
    DECLARE
      usage_found int;
    BEGIN
        -- Check that note is not used anywhere else
      usage_found = (select count(*) from knive_notes where note_id = OLD.note_id)
      IF (usage_found = 0) THEN
        DELETE from note where id = OLD.note_id    
      END IF;    
    
      RETURN NULL; -- result is ignored since this is an after trigger
    END;
    ## LANGUAGE plpgsql;
    
    CREATE TRIGGER knife_notes_deleted_trigger
    AFTER DELETE ON knife_notes
    FOR EACH ROW
    EXECUTE PROCEDURE try_to_delete_note();
    

    另请参见postgresql文档中的触发器示例。

    响应很好。事实上,您的响应使我意识到我的模型存在缺陷。模型应该是每个刀可以有多个注释,但一个注释只能与一个刀相关。我想通过在刀注释表中设置注释id可以强制执行此操作。这会改变删除孩子的方式吗另外,我更喜欢没有外键的“notes”表,并使用关系表,如knife_notes表来引用注释。另一种方法是为每个可以有注释的实体创建单独的notes表,我发现这更为复杂。如果对不同的实体使用注释,那么这是一个合理的模型。它只是无法级联delete,所以你必须使用触发器。我将附加我的答案来说明为什么更好一些。