如何改进此条件UPDATE查询?

时间:2018-02-16 09:34:40

标签: sql postgresql

我有一个包含多个列的表t,我们将它们命名为abc。我还有一个state列,表示当前状态。还有id列。

我想编写以下查询:始终更新列a,但仅当应用程序b仍等于数据库时才cstate state 的。这里,state列用于乐观锁定。

我写了这个查询如下:

UPDATE t
SET    a = $a$,
       b = (CASE WHEN state = $state$ THEN $b$ ELSE b END),
       c = (CASE WHEN state = $state$ THEN $c$ ELSE c END)
WHERE  id = $id$ AND
       (
         a != $a$ OR
         b != (CASE WHEN state = $state$ THEN $b$ ELSE b END) OR
         c != (CASE WHEN state = $state$ THEN $c$ ELSE c END)
       )

此处,$id$$a$,...是来自应用程序的输入变量。 WHERE子句的第二部分是为了避免无法有效更新任何内容的更新。

此查询按预期工作,但非常笨拙。我几次重复同样的情况。我正在寻找一种以更优雅的方式重写此查询的方法。如果这是一个简单的SELECT查询,我可以使用LATERAL JOIN执行某些操作,但我看不到如何在此处应用此内容。

如何改进此查询?

4 个答案:

答案 0 :(得分:1)

将查询拆分为两个:

UPDATE t
SET    a = $a$
WHERE  id = $id$

UPDATE t
SET    b = $b$,
       c = $c$
WHERE  id = $id$ AND
       state = $state$

如果你需要原子性,请包装一个事务。

答案 1 :(得分:1)

这似乎更清洁(未经测试):

WITH src AS (
        SELECT    $a$ AS a
       , (CASE WHEN state = $state$ THEN $b$ ELSE b END) AS b
       , (CASE WHEN state = $state$ THEN $c$ ELSE c END) AS c
        FROM t
        WHERE  id = $id$
        )
UPDATE t dst
SET a=src.a, b=src.b, c=src.c
FROM src
WHERE  dst.id = src.id
AND   (src.a, src.b, src.c) IS DISTINCT FROM (dst.a, dst.b, dst.c)
        ;

答案 2 :(得分:-1)

您需要的唯一过滤器是ID = $ id

案例陈述表示如果状态不匹配,请不要在更新中更改它,因此您不需要对其进行过滤。

修改

$updated->appendChild($client);
$updated->appendChild($clientID);
echo $xml->saveXML();

如果你做了更多,那么"总是更新"不一定是真的。

第3次尝试检查是否存在相同的可能性,但b或c更新。

答案 3 :(得分:-1)

编辑:我花了一些时间来实现我的错:这个问题显然是针对单个更新,而我的回答是尝试更新多行。但是,如果您需要为一组行执行此更新,您可以:

  • 将所需参数插入临时表
  • 在“t2”子查询中加入该表
  • 选择它的列(例如tempTable.b As tempB)
  • 替换参数(例如$ b $ - > t2.tempB)

UPDATE t
SET a=source.a,
    b=source.b,
    c=source.c
FROM 
    (
        SELECT 
            id,
            a, 
            (CASE WHEN UpdateCondition THEN $b$ ELSE b END) AS b,
            (CASE WHEN UpdateCondition THEN $c$ ELSE c END) AS c
        FROM 
            (  
                SELECT state = $state$ As UpdateCondition, * FROM t
            ) As t2
        WHERE 
            id = $id$ AND
            (
                a != $a$ OR
                b != (CASE WHEN UpdateCondition THEN $b$ ELSE b END) OR
                c != (CASE WHEN UpdateCondition THEN $c$ ELSE c END)
            ) AS source
WHERE t.id=source.id;

t2的子查询为您提供状态条件,并且每行只执行一次计算。

“source”的子查询为您提供映射值并过滤那些没有更改的值。