使用两个不同的 where 条件更新查询

Sch*_*ler 3 postgresql update

我想设置statusfalse所有行除一人外,应应设置为true。我怎样才能做到这一点?

这是我试过的查询:

UPDATE students set status = false where status = true and 
set status = true where _id = 1;
Run Code Online (Sandbox Code Playgroud)

Len*_*art 8

您可以使用 case 表达式:

UPDATE students 
    set status = CASE WHEN _ID = 1 THEN true
                                   ELSE false
                 END;
Run Code Online (Sandbox Code Playgroud)

稍微短一点(但可能不那么明显)是:

UPDATE students 
    set status = COALESCE(_ID = 1,false);
Run Code Online (Sandbox Code Playgroud)

如果 _ID 可以为 NULL,则需要 COALESCE。

有人可能会争辩说,没有必要一直更新状态(出于效率原因)。如果我们考虑到 _ID 和 status 都可以为空,则有 9 种不同的情况(我们让 _ID = 0 代表所有行,其中 _ID 不为空且 _ID <> 1)。

_ID    Status    Action
-----------------------
null   null      set false
null   true      set false
null   false     -
   0   null      set false
   0   true      set false
   0   false     -
   1   null      set true
   1   true      - 
   1   false     set true
Run Code Online (Sandbox Code Playgroud)

所有操作由以下人员处理:

set status = COALESCE(_ID = 1,false);
Run Code Online (Sandbox Code Playgroud)

所以我们需要过滤掉不应该发生更新的 3 种情况:

(null, false), (0, false), (1, true)
Run Code Online (Sandbox Code Playgroud)

换句话说,我们的WHERE子句应该包括其他 6 种组合:

UPDATE students 
    set status = COALESCE(_id = 1,false)
WHERE ((coalesce(_id, 0) = 1) <> coalesce(status,(coalesce(_id, 0) <> 1)))
Run Code Online (Sandbox Code Playgroud)

这不是微不足道的(IMO),即使它可能可以简化,我也不建议在任何实际情况下使用它(我建议首先禁止布尔属性的空值,但那是另一回事)。

使用真值表验证布尔表达式的一种有用技术(再次是 IMO)是对域使用 CTE 并调查结果。上面的例子:

with status (s) as ( values (null),(false),(true))
  ,     _id (i) as ( values (null),(0),(1))
select i, s from status cross join _id
where ((coalesce(i, 0) = 1) <> coalesce(s,(coalesce(i, 0) <> 1)));    
Run Code Online (Sandbox Code Playgroud)

IS DISTINCT FROM 正如@Erwin Brandstetter 所展示的那样,这是一个很好的抽象,在此类情况下非常有用。