3

ROLLBACK TO SAVEPOINTCASE可以吗?我的查询是

BEGIN;
SAVEPOINT my_savepoint;
INSERT INTO DPoint (uuid) VALUES ('5547f4b7-00b3-4aac-8ceb-c9ca163a0214')
ON CONFLICT (uuid) DO NOTHING;
WITH
 ins1 AS (INSERT INTO Point (latitude, longitude, srid)
VALUES (37.251667, 14.917222, 4326) RETURNING id),
 ins2 as (INSERT INTO SPoint (idPt, uuiddpt)
     VALUES ((SELECT id FROM ins1), '5547f4b7-00b3-4aac-8ceb-c9ca163a0214') RETURNING id),
 ins3 as (INSERT INTO Distance (idSpt, uuiddpt)
     VALUES ((SELECT id FROM ins2), '5547f4b7-00b3-4aac-8ceb-c9ca163a0214'))
INSERT INTO DPointTS (uuid, type, name, idPoint)
VALUES ('5547f4b7-00b3-4aac-8ceb-c9ca163a0214', NULL, NULL, (SELECT id FROM ins1));

SELECT CASE WHEN
(SELECT uuid FROM DPoint
WHERE uuid = '5547f4b7-00b3-4aac-8ceb-c9ca163a0214' )
is not NULL THEN ROLLBACK TO SAVEPOINT my_savepoint END;
COMMIT;

我的想法是:

再次尝试插入 DPoint.uuid = '5547f4b7-00b3-4aac-8ceb-c9ca163a0214' 时,无需插入 Point、SPoint、Distance、DPointTS。所以我想在事务中将这些插入回滚到 my_savepoint。也许知道我必须以什么方式重写我的代码?

编辑:

SELECT uuid IS NULL AS is_not_uuid FROM DPoint WHERE uuid = '5547f4b7-00b3-4aac-8ceb-c9ca163a0214';
\gset
\if :is_not_uuid
    \echo 'insert row to DPoint'
    INSERT INTO DPoint (uuid) VALUES ('5547f4b7-00b3-4aac-8ceb-c9ca163a0214');
    ... 
    my INSERT query

\endif

我在没有 SAVEPOINT 的情况下更新我的策略 - 如果 SELECT 查询返回TRUE我评估所有插入。我以什么方式执行查询,仅在命令行中?在 DataGRIP 中尝试 console.sql 时,它会引发错误 - 它会诚实地执行所有行,INSERT INTO DPoint (uuid)...如果该点已经存在,则会失败。我想以一种方式执行语句

4

1 回答 1

2

不,你不能那样做。

您将不得不编写客户端代码并使用条件处理。

例如psql

-- set the variable "want_rollback" to TRUE or FALSE
SELECT uuid IS NOT NULL AS want_rollback
FROM dpoint
WHERE uuid = '5547f4b7-00b3-4aac-8ceb-c9ca163a0214' \gset
\if :want_rollback
ROLLBACK TO SAVEPOINT my_savepoint;
\endif

有关以下内容的详细信息,请参阅文档\if

\if expression
\elif expression
\else
\endif

这组命令实现了可嵌套的条件块。条件块必须以 a 开头\if并以 . 结尾\endif。在这之间可以有任意数量的\elif子句,这些子句可以可选地后跟一个\else子句。普通查询和其他类型的反斜杠命令可能(并且通常确实)出现在形成条件块的命令之间。

\ifand命令读取它们的\elif参数并将它们评估为布尔表达式。如果表达式产生true,则处理正常继续;否则,将跳过行,直到达到匹配\elif\else、 或\endif。一旦\ifor\elif测试成功,\elif同一块中后续命令的参数不会被评估,而是被视为 false。\else仅当没有更早的匹配\if\elif成功时才处理an 之后的行。

or命令的expression参数受变量插值和反引号扩展的影响,就像任何其他反斜杠命令参数一样。之后,它被评估为开/关选项变量的值。因此,有效值是对以下之一的任何明确的不区分大小写的匹配:, , , , , , , 。例如,、和都将被视为。\if\eliftruefalse10onoffyesnotTtRtrue

未正确评估为真或假的表达式将生成警告并被视为假。

被跳过的行被正常解析以识别查询和反斜杠命令,但查询不会发送到服务器,并且除条件 ( \if, \elif, \else, \endif) 之外的反斜杠命令将被忽略。仅检查条件命令的有效嵌套。跳过的行中的变量引用不展开,也不执行反引号展开。

给定条件块的所有反斜杠命令必须出现在同一个源文件中。如果在所有本地 \if 块关闭之前在主输入文件或 \include ed 文件上达到 EOF,则 psql 将引发错误。

同一页还将解释\gset

于 2019-12-20T14:49:51.297 回答