从包含外键的表中删除数据

时间:2015-05-16 05:59:27

标签: sql postgresql foreign-keys sql-delete

我正在编写一个绘图表面,其中包含元素和连接。

表面上我的两个表格如下:

CREATE TABLE element
(
  elid character varying(60) NOT NULL,
  data json,
  surface_id character varying(60) NOT NULL,
  type character varying,
  CONSTRAINT element_primary_key PRIMARY KEY (elid),
)
CREATE TABLE connection
(
  from_elid character varying(60) NOT NULL,
  to_elid character varying(60) NOT NULL,
  CONSTRAINT from_to_element_id PRIMARY KEY (from_elid, to_elid),
  CONSTRAINT from_element_fk FOREIGN KEY (from_elid)
      REFERENCES element (elid) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE,
  CONSTRAINT to_element_fk FOREIGN KEY (to_elid)
      REFERENCES element (elid) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE
)

如果我删除表面上的元素,它也会删除相应的连接,这由connection约束表示。 在这种情况下,我检查具有相同surface_id的所有元素,并删除那些缺失的元素(以及它们的连接)。

但是如何在绘图表面上删除时明确删除连接?由于from_elidto_elid仍然存在于表element

编辑:为了保存绘图表面,客户端将它们之间的所有元素和连接发送到服务器。

数据库中的示例数据:

--------------------------------  ---------------------
|element                        | |connection         |
--------------------------------  ---------------------
|elid | data |surface_id |type  | |from_elid |to_elid |
--------------------------------- ---------------------
|e1   |{}    |s1         |xxx   | |e1        |e2      |
|e2   |{}    |s1         |xxx   | |e2        |e3      |
|e3   |{}    |s1         |xxx   | |e3        |e4      |
|e4   |{}    |s1         |xxx   | |..        |..      |
|e5   |{}    |s2         |xxx   | |e5        |e6      |
|e6   |{}    |s2         |xxx   | |e6        |e7      |
|..   |..    |..         |...   | |..        |..      |
--------------------------------- ---------------------

客户发送的示例数据:

{
  surface_id: 's1', 
  elements:['e1','e2','e3','e4'], 
  connections:[
    {from:'e2', to:'e3'},
    {from:'e3', to:'e4'}
  ]
}

在示例数据中,e1e2之间的关联缺失,这意味着它已在绘图表面上删除surface_id =' s1'并且必须从表connection中删除。如何使用给定数据实现这一点并且不使用surface_id =' s2'?

删除元素之间的连接

2 个答案:

答案 0 :(得分:1)

  

但是如何在绘图表面上删除时明确删除连接?由于from_elid和to_elid仍然存在于表元素

您误解了外键是如何工作的。从connectionelement的外键表示如果插入连接,则元素必须要求每个元素都存在连接。

因此,您可以随时从connection表中删除行。只要至少有一个使用该元素的连接,您就无法从element表中删除行。

修改

如果您的程序只获得“幸存”连接,您可以使用提供的信息删除过时的连接

假设您有三个连接,并且您不知道哪些是新的,哪些不是:

首先需要删除不存在的:

delete from connection 
where (from_elid, to_elid) not in ( ('e2', 'e3'), ('e3','e4'), ('e4','e1') )
  and exists (select 1 
              from element e 
              where e.elid in (connection.from_elid, connection.to_elid)
                and e.surface_id = 's1');

除了in子句中的元素之外,这将删除表面s1上元素的所有连接。

现在你需要从connection表中不存在的那个列表中插入那些连接 - 基本上是一个条件插入。这可以使用insert .. select

来完成
insert into connection (from_elid, to_elid)
select *
from (
  values ('e2', 'e3'), ('e3','e4'), ('e4','e1')
) as t (from_elid, to_elid)
where not exists (select *
                  from connection c
                  where (t.from_elid, t.to_elid) = (c.from_elid, c.to_elid));

您需要在多用户环境中正确处理唯一键冲突,因为其他事务可能会插入相同的信息。

SQLFiddle示例:http://sqlfiddle.com/#!15/64e7d/1

答案 1 :(得分:0)

  

但是如何在删除时明确删除连接   绘图表面?

你的意思是你想删除元素表中引用的elid条目后连接表中的那些外键条目?

在任何情况下,如果DDL不允许你想要实现的目标,你可以考虑使用BEFORE DELETE或AFTER DELETE之类的触发器,这样你就可以先清理元素表,然后再清理连接表或连接表。元素表。

相关问题