从 table 中删除外键为主的数据

Delete data from table with foreign keys as primary

我正在用元素和它们之间的连接编写绘图表面。

我的两个 tables 表面看起来像这样:

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 仍然存在于 table 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' 删除,必须也从 table connection 中删除。如何使用给定的数据实现这一点并且不删除 surface_id = 's2'?

元素之间的连接

But how do I delete connections explicitly when being deleted on the drawing surface? Since from_elid and to_elid are still present in the table element

您误解了外键的工作原理。从 connectionelement 的外键声明如果插入连接,元素 必须 存在。它 要求每个元素都存在一个连接。

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


编辑

如果您的程序只获得 "surviving" 个连接,您可以使用提供的信息删除过时的连接

假设您获得了三个连接并且您不知道它们中哪些是新的哪些不是:

您首先需要删除不存在的:

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

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

现在您需要从该列表中插入那些 connection table 中尚不存在的连接 - 基本上是有条件的插入。这可以使用 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

But how do I delete connections explicitly when being deleted on the drawing surface?

您的意思是要在删除元素 table 中引用的 elid 条目后删除连接 table 中的那些外键条目?

无论如何,如果DDL不允许你达到你想要的效果,你可以考虑使用像BEFORE DELETE或AFTER DELETE这样的触发器,这样你就可以先清理元素table然后再清理元素 table.

之后的连接 table 或连接 table