从 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_elid
和 to_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'}
]
}
示例数据中缺少 e1
和 e2
之间的连接,这意味着它已在绘图表面上用 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
您误解了外键的工作原理。从 connection
到 element
的外键声明如果插入连接,元素 必须 存在。它不 要求每个元素都存在一个连接。
因此您可以随时从 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
我正在用元素和它们之间的连接编写绘图表面。
我的两个 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_elid
和 to_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'}
]
}
示例数据中缺少 e1
和 e2
之间的连接,这意味着它已在绘图表面上用 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
您误解了外键的工作原理。从 connection
到 element
的外键声明如果插入连接,元素 必须 存在。它不 要求每个元素都存在一个连接。
因此您可以随时从 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