use*_*766 23 sql postgresql foreign-keys sql-delete
我有这些表:
event (evt_id, evt_code, reg_id) magnitude (mag_id, evt_id, value) trace (trace_id, pt_id) point (pt_id, evt_id)
我想删除所有与之相关的表中的所有行evt_id=1139
.
我该怎么做?
Jus*_*ony 21
如果您可以控制架构,我会使架构使用级联删除.
从文章(为您的示例翻译更相关的部分)
CREATE TABLE point
(
pt_id integer PRIMARY KEY,
evt_id integer REFERENCES event ON DELETE CASCADE
)
Run Code Online (Sandbox Code Playgroud)
如果您设置了级联,则只需从主事件表中删除,所有其他表将自动清除
否则,您需要先删除所有引用,然后删除主表.您应该在一个事务中执行此操作以保持数据一致
BEGIN;
DELETE FROM trace WHERE EXISTS
(SELECT 1 FROM point WHERE evt_id = 1139 AND trace.pt_id = point.pt_id);
DELETE FROM point where evt_id = 1139;
DELETE FROM magnitude where evt_id = 1139;
DELETE FROM event where evt_id = 1139;
COMMIT;
Run Code Online (Sandbox Code Playgroud)
Erw*_*ter 14
您问题中唯一的非平凡元素是从表中删除trace
.我想假设trace.pt_id
引用是安全的point.pt_id
吗?
您要么定义一个外键ON DELETE CASCADE
而忘记该表trace
(正如@kevin已经指出的那样),或者您必须手动处理依赖行.
从PostgreSQL 9.1开始,您可以使用数据修改CTE:
BEGIN;
WITH x AS (
DELETE FROM point WHERE evt_id = 1139
RETURNING pt_id
)
DELETE FROM trace
USING x
WHERE trace.pt_id = x.pt_id;
DELETE FROM magnitude WHERE evt_id = 1139;
DELETE FROM event WHERE evt_id = 1139;
COMMIT;
Run Code Online (Sandbox Code Playgroud)
在RETURNING子句中的DELETE FROM point
回报所有受影响pt_id
-这些都是交替使用,从删除所有相应的行trace
.
您没有提到并发性是否是您的问题.如果是,并且如果要在删除之间的短时间窗口中避免可能的结果,其中行evt_id = 1139
已存在于一个表中而已从另一个表中删除,则将其全部包装到事务中.
如果您不关心,请忽略BEGIN
和COMMIT
.
为避免死锁,请始终使用相同的delete语句序列(在所有并发事务中).这避免了一个事务将在一个表中开始删除,另一个表中的下一个事务然后每个事务将等待另一个事务的情况.
如果可以将要删除的行设想为层次结构,则可以使用ON DELETE CASCADE子句为关系定义FOREIGN KEY约束。删除顶部的行将向下层叠并全部删除。
http://www.postgresql.org/docs/9.1/static/ddl-constraints.html#DDL-CONSTRAINTS-FK