从 temp table 更新每组选择 "last" 行
UPDATE from temp table picking the "last" row per group
假设有一个 table 数据:
+----+-------+
| id | value |
+----+-------+
| 1 | 0 |
| 2 | 0 |
+----+-------+
我需要进行批量更新。并使用 COPY FROM STDIN
不受约束地快速插入临时 table,因此它可以在 id
列
中包含重复值
要更新的温度 table:
+----+-------+
| id | value |
+----+-------+
| 1 | 1 |
| 2 | 1 |
| 1 | 2 |
| 2 | 2 |
+----+-------+
如果我只是 运行 查询,例如:
UPDATE test target SET value = source.value FROM tmp_test source WHERE target.id = source.id;
我得到了错误的结果:
+----+-------+
| id | value |
+----+-------+
| 1 | 1 |
| 2 | 1 |
+----+-------+
我需要目标 table 包含最后出现在临时 table 中的值。
考虑到目标 table 可能包含数百万条记录,而临时 table 可能包含数万条记录,最有效的方法是什么?**
假设您想要从最后插入临时 table 的行中获取 value
,实际上,您可以(滥用)使用系统列 ctid
,表示物理位置:
UPDATE test AS target
SET value = source.value
FROM (
SELECT DISTINCT ON (id)
id, value
FROM tmp_test
ORDER BY id, ctid DESC
) source
WHERE target.id = source.id
AND target.value <> source.value; -- skip empty updates
关于DISTINCT ON
:
- Select first row in each GROUP BY group?
这建立在实现细节之上,并且不受 SQL 标准的支持。如果某些插入方法不应该按顺序写入行(比如未来的“平行”INSERT
),它就会中断。目前,它应该工作。关于 ctid
:
如果你想要一种安全的方式,你需要添加一些用户列来表示行的顺序,比如 serial
列。但你真的在乎吗?您的决胜局似乎相当武断。参见:
- Temporary sequence within a SELECT
AND target.value <> source.value
跳过空更新 - 假设两列都是 NOT NULL
。否则,使用:
AND target.value IS DISTINCT FROM source.value
参见:
- How do I (or can I) SELECT DISTINCT on multiple columns?
假设有一个 table 数据:
+----+-------+
| id | value |
+----+-------+
| 1 | 0 |
| 2 | 0 |
+----+-------+
我需要进行批量更新。并使用 COPY FROM STDIN
不受约束地快速插入临时 table,因此它可以在 id
列
要更新的温度 table:
+----+-------+
| id | value |
+----+-------+
| 1 | 1 |
| 2 | 1 |
| 1 | 2 |
| 2 | 2 |
+----+-------+
如果我只是 运行 查询,例如:
UPDATE test target SET value = source.value FROM tmp_test source WHERE target.id = source.id;
我得到了错误的结果:
+----+-------+
| id | value |
+----+-------+
| 1 | 1 |
| 2 | 1 |
+----+-------+
我需要目标 table 包含最后出现在临时 table 中的值。
考虑到目标 table 可能包含数百万条记录,而临时 table 可能包含数万条记录,最有效的方法是什么?**
假设您想要从最后插入临时 table 的行中获取 value
,实际上,您可以(滥用)使用系统列 ctid
,表示物理位置:
UPDATE test AS target
SET value = source.value
FROM (
SELECT DISTINCT ON (id)
id, value
FROM tmp_test
ORDER BY id, ctid DESC
) source
WHERE target.id = source.id
AND target.value <> source.value; -- skip empty updates
关于DISTINCT ON
:
- Select first row in each GROUP BY group?
这建立在实现细节之上,并且不受 SQL 标准的支持。如果某些插入方法不应该按顺序写入行(比如未来的“平行”INSERT
),它就会中断。目前,它应该工作。关于 ctid
:
如果你想要一种安全的方式,你需要添加一些用户列来表示行的顺序,比如 serial
列。但你真的在乎吗?您的决胜局似乎相当武断。参见:
- Temporary sequence within a SELECT
AND target.value <> source.value
跳过空更新 - 假设两列都是 NOT NULL
。否则,使用:
AND target.value IS DISTINCT FROM source.value
参见:
- How do I (or can I) SELECT DISTINCT on multiple columns?