我想使用 Postgres 中的 CTE 删除然后插入单个语句。我们可以使用显式事务和 2 个语句,但希望尽可能避免这种情况。我不知道是否会删除 0 行或 1+ 行,因此我认为我无法使用单个 WHERE EXISTS 或 WHERE NOT EXISTS 来确保 CTE 中的删除语句首先运行。这与我的设想类似:
WITH deletions AS (
DELETE FROM foo WHERE a = 'abc' and b = 2
)
INSERT INTO FOO (a, b, c) VALUES ('abc', 2, 'new value')
Run Code Online (Sandbox Code Playgroud)
但我需要一种方法来强制 CTE 首先运行。表上不存在会在同一事务中尝试两次更新同一记录时产生问题的 pk。
如果没有任何UNIQUE
限制,您的原始查询就可以正常工作。见下文。
我会放入一个单独的 CTE 来一次性提供所有输入值:
WITH input(a, b, c) AS (VALUES ('abc', 2, 'new value')) -- provide values once
, del AS (
DELETE FROM foo AS f
USING input i
WHERE f.a = i.a
AND f.b = i.b
)
INSERT INTO foo (a, b, c)
TABLE input;
Run Code Online (Sandbox Code Playgroud)
无法DELETE
从INSERT
同一语句中删除行,因为两者都看到基础表的相同快照。这意味着,无法看到其他 CTE 中DELETE
输入的行。INSERT
两者实际上是同时执行的。有关的:
这也是为什么这不能与UNIQUE
上的索引一起使用的原因(a.b)
。始终强制执行唯一性。仍然会INSERT
看到其他 CTE 中的行被删除。显而易见的替代方案是 UPSERT。但事实并非如此,因为您提到没有 PK 并且可以DELETE
删除 0-n 行。
正如 a_horse 评论的那样:不过,可以使用可延迟的约束。看:
但是可延迟约束的成本要高得多,并且不能与 FK 约束一起使用,也不能作为 UPSERT 语句中的仲裁者......
请注意,独立VALUES
表达式可能需要显式类型转换。看:
有关的:
也就是说,我不明白这比单个事务中的aDELETE
和 a 有何优越之处- 这也适用于约束。您评论道:INSERT
UNIQUE
通过单个语句和我们的数据库库使用数据库参数要容易得多。
如果经常使用该语句,请考虑使用函数:
CREATE OR REPLACE FUNCTION f_foo_delins(_a text, _b int, _c text) -- actual types
RETURNS void LANGUAGE sql AS
$func$
DELETE FROM foo
WHERE a = _a
AND b = _b;
INSERT INTO foo ( a, b, c)
VALUES (_a, _b, _c);
$func$;
Run Code Online (Sandbox Code Playgroud)
那么调用就简单了:
SELECT f_foo_delins('abc', 3, 'new value');
Run Code Online (Sandbox Code Playgroud)
如果您只需要在某些会话中使用它,则可以选择临时功能。看:
或者带有上述 CTE 的准备好的语句:
PREPARE foo_delins(text, int, text) AS
WITH del AS (
DELETE FROM foo
WHERE a = $1
AND b = $2
)
INSERT INTO foo ( a, b, c)
VALUES ($1, $2, $3);
Run Code Online (Sandbox Code Playgroud)
称呼:
EXECUTE foo_delins('abc', 4, 'new value');
Run Code Online (Sandbox Code Playgroud)
大多数语言都有自己的准备好的语句的实现,使用libpq
...
准备好的语句和函数知道它们的输入类型。不需要显式类型转换(特殊情况除外)。
有关的:
小智 0
您可以返回 CTE 中删除的任何内容并将其插入表中。
WITH deletions AS (
DELETE FROM foo WHERE a = 'abc' and b = 2 returning a,b
)
INSERT INTO FOO (a, b, c)
select a,b,'new value' from deletions;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
12893 次 |
最近记录: |