仅当所有记录都满足一个条件时才对多条记录执行更新

时间:2021-06-03 07:00:50

标签: sql postgresql

我想更新一批行,但前提是该批中的所有行都符合条件。

示例表:

create table thing (
    id int primary key,
    ref int
);

示例数据:

INSERT INTO thing (id, ref)
VALUES
    (1, NULL)
    , (2, NULL)
    , (3, 1)
    , (4, 1);

错误查询示例 - 这会更新第 1 行和第 2 行,但会保留第 3 行(不需要):

UPDATE thing
SET ref = 2
WHERE id = ANY(ARRAY[1,2,3]) AND ref IS NULL;

目标:单个查询,其中之一:更新所有匹配的行;或 2:什么都不做,并以某种方式通知我(例如更新了 0 行)所以可以发出警告。

编辑 - 此处示例:http://sqlfiddle.com/#!17/f9ad9/4

3 个答案:

答案 0 :(得分:1)

如果存在满足部分 WHERE 条件但不是所有连词项的行,则更新全部或不更新。

UPDATE thing
SET ref = 2
WHERE id = ANY(ARRAY[1,2,3]) AND ref IS NULL
AND NOT EXISTS (select 1 from thing t where t.id = ANY(ARRAY[1,2,3]) and t.ref IS NOT NULL or not(t.id = ANY(ARRAY[1,2,3])) AND t.ref IS NULL)

或者,当 WHERE 中的原始连词有两个以上的词时

UPDATE thing
SET ref = 2
WHERE id = ANY(ARRAY[1,2,3]) AND ref IS NULL
AND NOT EXISTS (select 1 
                from thing t 
                where ( t.id = ANY(ARRAY[1,2,3]) or t.ref IS NULL)-- disjunction of terms of original conjunction
                  and ( not(t.id = ANY(ARRAY[1,2,3]) or t.ref IS NOT NULL) --disjunction of negations of terms of original conjunction
               ); 

db<>fiddle

答案 1 :(得分:1)

  • 首先确定batch中的记录数和其中需要更新的记录数(pre_condition CTE);
  • 仅当这些数字相同时才更新;
  • 返回更新行的 id-s 作为结果
with pre_condition as
(
 select
        count(*) filter (where id = ANY(ARRAY[1,2,3])) batch_count,
        count(*) filter (where id = ANY(ARRAY[1,2,3]) AND ref IS NULL) set_count
 from thing
)

UPDATE thing
SET ref = 2
WHERE id = ANY(ARRAY[1,2,3]) AND ref IS NULL

and (select batch_count = set_count from pre_condition)
returning id;

答案 2 :(得分:0)

这是我解决自己问题的方法:W3Schools JSON.Parse()

UPDATE thing
SET ref = 2
WHERE id = ANY(ARRAY[1,2,3]) AND ref IS NULL
AND NOT EXISTS ( -- if anything returns here — nothing will update
  SELECT 1
  FROM thing
  WHERE id = ANY(ARRAY[1,2,3]) AND ref IS NOT NULL
)
RETURNING id;