下面的工作吗?
WITH upd AS (
UPDATE main_stat t
SET counter = s.counter
FROM tmp_stat s
WHERE t.date = s.date
AND t.site_id = s.site_id
AND t.ip = s.ip
AND t.block_id = s.block_id
RETURNING s.date, s.site_id, s.ip, s.block_id, s.counter
)
INSERT INTO main_stat
SELECT s.mydate, s.site_id, s.ip, s.block_id, s.counter
FROM tmp_stat s
LEFT JOIN upd ON (upd.date = s.date and upd.site_id = s.site_id and upd.ip = s.ip and upd.block_id = s.block_id)
WHERE upd.date IS NULL
;
更新:
看起来这仅适用于 9.1 或更高版本。
使用 just-somebody 的建议WHERE (t.date, t.site_id, t.ip, t.block_id) = (s.date, s.site_id, s.ip, s.block_id)
似乎可以提供更好的性能。
WITH upd AS (
UPDATE main_stat t
SET counter = s.counter
FROM tmp_stat s
WHERE ( t.date, t.site_id, t.ip, t.block_id ) = ( s.date, s.site_id, s.ip, s.block_id )
RETURNING s.date, s.site_id, s.ip, s.block_id
)
INSERT INTO main_stat
SELECT s.date, s.site_id, s.ip, s.block_id, s.counter
FROM tmp_stat s
LEFT JOIN upd
ON ( upd.date = s.date
AND upd.site_id = s.site_id
AND upd.ip = s.ip
AND upd.block_id = s.block_id )
WHERE upd.date IS NULL
;
这里发生的是我们使用 CTE 执行 UPDATE,CTE 返回更新行的标识列。
然后 INSERT 使用更新的行信息过滤 tmp_stat 以仅插入新记录。
Dimitri Fontaine 在此博客条目中介绍了一些并发警告。
有关 CTE 的更多信息可以在 Postgresql文档中找到。