RaR*_*RaR 10 postgresql greatest-n-per-group
我有两个表叫做record
和record_history
。对于每条记录,可能有多个历史记录。它们可以通过id
和 连接record_id
。我想record
用最近的record_history
数据获取所有的条目。我已经创建了这样的查询,
SELECT rec.id, rec.name, rech1.data AS last_history_data
FROM record rec
LEFT OUTER JOIN record_history rech1 ON (rec.id = rech1.record_id)
LEFT OUTER JOIN record_history rech2 ON (rec.id = rech2.record_id AND rech2.ts > rech1.ts)
WHERE rech2.id IS NULL
ORDER BY rec.id DESC
Run Code Online (Sandbox Code Playgroud)
在这里,我通过ts
. 只要没有重复的ts
条目,这就会起作用。如果最近的时间戳在 中重复record_history
,则此查询将返回多于一行的记录。我们如何在左连接上应用限制来限制重复行?
ype*_*eᵀᴹ 14
除非您使用的是非常旧版本的 Postgres,否则您不需要双重连接。您可以通过使用LATERAL
join获得相同的结果。
通过添加除rec.id = rech2.record_id
. 使用LATERAL
join 方法,LIMIT
无论如何都要避免它。横向子查询只能返回 1 行。我们可以添加第二个条件,以便选择是确定性的(来自具有相同时间戳的两行或更多行):
SELECT rec.id, rec.name, rech.data AS last_history_data
FROM record AS rec
LEFT OUTER JOIN LATERAL
( SELECT rech.data
FROM record_history AS rech
WHERE rec.id = rech.record_id
ORDER BY rech.ts DESC
-- ,rech.id DESC -- optional
LIMIT 1
) AS rech
ON TRUE
ORDER BY rec.id DESC ;
Run Code Online (Sandbox Code Playgroud)
关于如何使用原始方法(2 个连接和IS NULL
检查)执行此操作,您可以更改ON
条件 - 假设id
历史表中有一个列,以便(id)
或至少(ts, id)
是唯一的:
LEFT OUTER JOIN record_history rech2
ON rec.id = rech2.record_id
AND (rech2.ts > rech1.ts OR rech2.ts = rech1.ts AND rech2.id > rech1.id)
Run Code Online (Sandbox Code Playgroud)
顺便说一下,您可以替换第二个LEFT
连接并IS NULL
使用NOT EXISTS
具有相同结果和可能相似效率的子查询进行检查(或者甚至使用NOT IN
子查询,尽管这需要额外注意可空列,不推荐)。
归档时间: |
|
查看次数: |
32234 次 |
最近记录: |