如何从多个表中删除数据?

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已存在于一个表中而已从另一个表中删除,则将其全部包装到事务中.
如果您不关心,请忽略BEGINCOMMIT.

为避免死锁,请始终使用相同的delete语句序列(在所有并发事务中).这避免了一个事务将在一个表中开始删除,另一个表中的下一个事务然后每个事务将等待另一个事务的情况.


kgr*_*ttn 5

如果可以将要删除的行设想为层次结构,则可以使用ON DELETE CASCADE子句为关系定义FOREIGN KEY约束。删除顶部的行将向下层叠并全部删除。

http://www.postgresql.org/docs/9.1/static/ddl-constraints.html#DDL-CONSTRAINTS-FK