我有两个表t1和t2。我这样删除某些t2行:
delete from t2 where expiry<NOW();
t1和t2共有一列id
。但是不确定t2中的id将始终在t1中具有相应的行。执行上述语句时,我还想根据id
删除t1中的相应行(如果它们存在,则仅从t2删除)。如何才能做到这一点?是否可以编写单个查询来完成这两项操作?
答案 0 :(得分:2)
我至少看到了三种好方法 - 取决于你问题中遗漏的更多细节。我建立在你的榜样上:
t2
是母亲表t1
孩子ON CASCADE DELETE
试验台:
CREATE TABLE t2 (
id serial PRIMARY KEY -- primary or unique key needed
,expiry timestamp
);
CREATE TABLE t1(
id int references t1(id) ON DELETE CASCADE -- ON UPDATE CASCADE, too?
);
填充表格:
INSERT INTO t2(expiry)
SELECT (now() + g * interval '1h')
FROM generate_series(1, 10) g; -- 10 arbitrary rows
INSERT INTO t1(id)
SELECT id FROM t2 WHERE id%2 = 0; -- pick even numbers for t1
SELECT * FROM t1;
如果从t2删除行,则会自动删除t1中的相应行:
DELETE FROM t2 WHERE id IN (1,2,3,4,5);
-- rows 2,4 in `t1` are deleted automatically
将这样的外键约束添加到现有表中:
ALTER TABLE t1 ADD CONSTRAINT t1_id_fkey FOREIGN KEY (id)
REFERENCES t2 (id) ON DELETE CASCADE;
当然,外键需要t1.id
上的唯一键或主键。但你可能在这样的场景中有这个。
如果t2.id
中的值不唯一,或者t1.id
中的值违反了外键约束,则可以改为创建触发器AFTER DELETE。
触发功能:
CREATE OR REPLACE FUNCTION t2_delaft
LANGUAGE plpgsql VOLATILE
RETURNS trigger AS
$BODY$
BEGIN
DELETE FROM t1
WHERE t1.id = OLD.id;
RETURN NULL; -- AFTER trigger can return NULL
END;
$BODY$
触发:
CREATE TRIGGER delaft
AFTER DELETE ON t2
FOR EACH ROW EXECUTE PROCEDURE t2_delaft();
您还可以实施RULE。但我发现触发器通常更容易处理。
原谅我最后给出最简单的答案。无论如何,这都有效 - 只要您使用的是PostgreSQL 9.1或更高版本:
WITH x AS (
DELETE FROM t1
WHERE id IN (1,2,3,4,5)
RETURNING id
)
DELETE FROM t2
USING x
WHERE t2.id = x.id;