【问题标题】:Usage ROLLBACK TO SAVEPOINT with condition使用 ROLLBACK TO SAVEPOINT 条件
【发布时间】:2020-04-13 01:50:54
【问题描述】:

CASE 可以ROLLBACK TO SAVEPOINT 吗? 我的查询是

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)... 中失败,以防该点已经存在。我想以一种方式执行语句

【问题讨论】:

    标签: sql postgresql case savepoints


    【解决方案1】:

    不,你不能那样做。

    您必须编写客户端代码并使用条件处理。

    例如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的详细信息,请参阅the documentation

    \if <strong><em>expression</em></strong>
    \elif <strong><em>expression</em></strong>
    \else
    \endif

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

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

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

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

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

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

    同一页也会解释\gset

    【讨论】:

    • 感谢您的快速答复!你能告诉我更多关于条件处理的细节吗?我没有注意到使用 want_rollback, \gset...
    • 我添加了一些文档。
    • \if 仅适用于psql。如果您在不同的环境中工作,则必须使用该环境中可用的编程语言。
    猜你喜欢
    • 1970-01-01
    • 2019-01-29
    • 2017-01-20
    • 2014-05-11
    • 1970-01-01
    • 1970-01-01
    • 2011-08-21
    • 2018-10-03
    • 2020-03-29
    相关资源
    最近更新 更多