我想设置status
到false
所有行除一人外,应应设置为true
。我怎样才能做到这一点?
这是我试过的查询:
UPDATE students set status = false where status = true and
set status = true where _id = 1;
Run Code Online (Sandbox Code Playgroud)
您可以使用 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 所展示的那样,这是一个很好的抽象,在此类情况下非常有用。