对于表
line
中的每一行,表 line_version
中可以有很多行。我只需要为每个 line
行找到 N(比方说 2)“最新”行。这里的最新是指最大的ID。
例如,这就是
line_version
表行的样子(line_id
引用 line
表):
id | line_id
-------+---------
10 | 1
20 | 1
30 | 1
40 | 1
50 | 2
60 | 2
70 | 2
查找每
line_version
行最新的 2 个 line
行 ID,应该是 (30, 40, 60, 70)
。
在全球范围内,我只需执行以下操作即可获得 2 个最新的:
SELECT id from line_version ORDER BY id DESC LIMIT 2
但是我怎样才能获得最新的2个
line_id
?
您可以使用下面的条件 rownumber>=count1-(N-1)。sql 小提琴here。对于最后一行,您可以使用 rownumber>=count1。最后两行 rownumber>=count1-1,三行 rownumber >=计数1-2
with data as (select
10 id , 1 line_id union all
select 20 , 1 union all
select 30 , 1 union all
select 40 , 1 union all
select 50 , 2 union all
select 60 , 2 union all
select 70 , 2),
subset as (select a.*,ROW_NUMBER() over(partition by line_id order by id ) rownumber,count(id) over(partition by line_id) count1 from data a)
select id,line_id from subset where rownumber>=count1-1;
为了提高性能,您可以使用下面的 rownumber 来取消 count1 <=N.
with data as (select
10 id , 1 line_id union all
select 20 , 1 union all
select 30 , 1 union all
select 40 , 1 union all
select 50 , 2 union all
select 60 , 2 union all
select 70 , 2),
subset as (select a.*,ROW_NUMBER()
over(partition by line_id order by id desc)
rownumber from data a)
select id,line_id from subset
where rownumber<=2 order by line_id,id;
如果版本数量远多于每行两个版本,请避免对
line_version
进行顺序扫描。这个使用 LATERAL
子查询的查询就是这样做的,并且应该更高效:
SELECT lv.*
FROM line l
CROSS JOIN LATERAL (
SELECT lv.id
FROM line_version lv
WHERE lv.line_id = l.line_id
ORDER BY lv.id DESC NULLS LAST
LIMIT 2 -- your pick!
) lv
-- ORDER BY ???
我添加
NULLS LAST
主要是为了防止可能出现的空值,您尚未排除这种情况。参见:
确保 line_version
上有
index,并以
line_id
作为前导索引字段。理想情况下:
CREATE INDEX line_version_line_id_id_idx ON line_version(line_id DESC NULLS LAST) INCLUDE (id);
参见: