更新以在单个语句中切换布尔列
Posted
技术标签:
【中文标题】更新以在单个语句中切换布尔列【英文标题】:Update to toggle a boolean column in a single statement 【发布时间】:2019-03-22 01:08:42 【问题描述】:如何以最有效的方式组合在单个 sql 语句中的两个查询?
UPDATE TABLE_A a
SET a.is_active = FALSE
WHERE a.id IN (SELECT id FROM TABLE_B);
同样,但切换其余id
s的标志:
UPDATE TABLE_A a
SET a.is_active = TRUE
WHERE a.id NOT IN (SELECT id FROM TABLE_B);
【问题讨论】:
您的第二个查询不会切换值,它只是将其设置为 true。 【参考方案1】:在 Postgres 中,您可以在 UPDATE
语句中使用 LEFT JOIN
,语法如下:
UPDATE a
SET a.is_active = CASE WHEN b.id IS NULL THEN FALSE ELSE TRUE
FROM TABLE_A a
LEFT JOIN TABLE_B b ON a.id = b.id
【讨论】:
【参考方案2】:好吧,你可以使用CASE
表达式:
UPDATE TABLE_A a
SET a.is_active = (CASE WHEN a.id IN (SELECT id FROM TABLE_B)
THEN FALSE ELSE TRUE
END);
在 Postgres 中,您可以将其简化为:
UPDATE TABLE_A
SET is_active = (id IN (SELECT b.id FROM TABLE_B b));
【讨论】:
【参考方案3】:UPDATE table_a a
SET is_active = NOT EXISTS (SELECT FROM table_b b WHERE b.id = a.id);
假设id
两个列都是NOT NULL
。
否则,带有table_a.id IS NULL
的行在您的原始文件中完全未更新,因为NULL
既不是IN
也不是NOT IN
任何集合。
如果table_b.id
中有任何NULL
值none 您的行以a.is_active = TRUE
结尾,因为a.id NOT IN (SELECT id FROM TABLE_B)
是FALSE
或NULL
但绝不是@ 987654336@ 在这种情况下。 NOT IN
因这种“陷阱”而臭名昭著。相关:
这个带有EXISTS
的查询会更新所有行。 table_a.id IS NULL
的结果是 is_active = TRUE
,就像在 table_b
中找不到的其他 ID 一样,table_b.id
中的 NULL 值没有任何区别。
EXISTS
也很有吸引力,特别是如果table_b.id
中可以有(许多)重复值 - 更好的性能。 table_b.id
无论如何都应该被索引。
【讨论】:
【参考方案4】:您可以在两个表上使用连接,然后使用 case 语句来确定 TABLE B 中是否存在值:
CREATE TABLE #TABLE_A (Id int, is_active bit)
CREATE TABLE #TABLE_B (Id int)
INSERT INTO #Table_A
VALUES (1, NULL)
,(2, NULL)
,(3, NULL)
,(4, NULL)
INSERT INTO #TABLE_B
VALUES (1),(3)
SELECT * FROM #TABLE_A
UPDATE a
SET is_active = (CASE WHEN b.id IS NULL THEN 1 ELSE 0 END)
FROM #TABLE_A a
LEFT OUTER JOIN #TABLE_B b
ON a.id = b.Id
SELECT * FROM #TABLE_A
【讨论】:
以上是关于更新以在单个语句中切换布尔列的主要内容,如果未能解决你的问题,请参考以下文章
Swift 模式匹配 - 在单个语句中切换、向下转换和可选绑定