我正在尝试构建一个查询,其中我使用table_a
和table_b
中包含的数据更新table_c
。
我发现的所有UPDATE ... FROM
文档和问题似乎都专注于通过加入table_a
来更新table_c
table_b
中的数据。我不希望这样,我需要使用table_b
和table_c
中包含的数据,这些数据都已加入table_a
示例选择将是:
SELECT
a.id
, b.counted as count_b
, c.counted as count_c
FROM
table_a a
LEFT JOIN
table_b b on a.id = b.id
LEFT JOIN
table_c c on a.id = c.id
;
id | count_b | count_c
----+---------+---------
34 | 6 | 2
43 | 16 | 2
45 | 33 | 5
工作'一个表' -updates是:
UPDATE table_a SET count_b = table_b.counted
FROM table_b WHERE table_a.id = table_b.id;
UPDATE table_a SET count_c = table_c.counted
FROM table_c WHERE table_a.id = table_c.id;
但是我想将它们结合起来以提高效率(更新是插入+删除,因此可以节省一些费用。但我似乎无法弄清楚如何加入table_a
中UPDATE ... FROM
上的两个表格。
我可以用子查询来处理这个问题 - 但我更愿意避免这种情况。
答案 0 :(得分:1)
为了缩短我的冗长答案,我使用表名a
,b
,c
。
如果a.id
,b.id
和c.id
UNIQUE
(但可能会丢失):
基本形式,有很多警告(继续阅读!):
UPDATE a
SET count_b = b.counted
, count_c = c.counted
FROM b
FULL JOIN c USING (id)
WHERE a.id = COALESCE(b.id, c.id)
;
如果任何id
列不是UNIQUE
,则无法正常工作 - 但两者都不会分开更新。
如果没有任何实际更改(所有counted
列与a
中的列相同),您只需创建一个完整成本的死行。如果情况确实如此,并且您想避免它,请附加一个WHERE
子句:
AND (a.count_b <> b.counted OR
a.count_c <> c.counted) -- simple form with all columns NOT NULL
FULL [OUTER] JOIN
如果某些表,而不是所有表(两个源表的简单情况下的一个),它就能正常工作没有相同id
的行。它有效地模拟了您想到的多个LEFT JOIN
,但有一个很小但重要的差异:您会从缺少行的表中获取幻像NULL
值。使用COALESCE
抓住它:
SET count_b = COALESCE(b.counted, a.count_b)
如果counted
可以是NULL
,则仍然是一个极端情况。 COALESCE
无法区分两种情况:
1. b.counted IS NULL
。
2. b.counted
不存在
如果您需要区分,请改为使用CASE
语句:
SET count_b = CASE WHEN b.id IS NULL THEN a.count_b ELSE b.counted END
相应地调整WHERE
条款
完整版,涵盖所有NULL
个案例并避免空更新:
UPDATE a
SET count_b = CASE WHEN b.id IS NULL THEN a.count_b ELSE b.counted END
, count_c = CASE WHEN c.id IS NULL THEN a.count_b ELSE c.counted END
FROM b
FULL JOIN c USING (id)
WHERE a.id = COALESCE(b.id, c.id)
AND (b.id IS NOT NULL AND b.counted IS DISTINCT FROM a.count_b OR
c.id IS NOT NULL AND c.counted IS DISTINCT FROM a.count_c)
;
看起来很复杂,但如果源表之间存在大量重叠,则应该更快。
如果任何源表中没有匹配的id
,则a
中的相应行不会更新,这通常是您想要的。您可以使用相关子查询来更新所有行,无论如何 - 这通常是您不想要的,但您的情况可能会有所不同。对于大表,相关的子查询通常也要昂贵得多。
UPDATE a
SET count_b = (SELECT b.counted FROM b WHERE b.id = a.id)
, count_c = (SELECT c.counted FROM c WHERE c.id = a.id)
同样,您可以使用以下内容来避免NULL
值:
SET count_b = COALESCE ((SELECT b.counted ...), count_b)
仍然会浪费您尝试最小化的空更新。您可以为{...}添加WHERE
子句EXISTS
。
答案 1 :(得分:0)
不是确切的查询,但更像是一个例子。您可以尝试如下,在内部查询中获取counted
和table_b
的{{1}}列,并在更新时将其加入table_b
。
table_a