我正在尝试获取存储在数据库表中的有序集的最后一个元素。顺序由表中的一列定义。此外,该表包含多个集合,因此我想要每个集合的最后一个。
作为示例,请考虑下表:
benchmarks=# select id,sorter from aggtest ;
id | sorter
----+--------
1 | 1
3 | 1
5 | 1
2 | 2
7 | 2
4 | 1
6 | 2
(7 rows)
排序器 1 和 2 定义每个集合,集合按 id 列排序。为了获取每个集合的最后一个元素,我定义了一个聚合函数:
CREATE FUNCTION public.last_agg ( anyelement, anyelement )
RETURNS anyelement LANGUAGE sql IMMUTABLE STRICT AS $$
SELECT $2;
$$;
CREATE AGGREGATE public.last (
sfunc = public.last_agg,
basetype = anyelement,
stype = anyelement
);
如上所述here .
但是当我使用它时我得到:
benchmarks=# select last(id),sorter from aggtest group by sorter order by sorter;
last | sorter
------+--------
4 | 1
6 | 2
(2 rows)
但是,我想获取 (5,1)
和 (7,2)
,因为它们是集合中的最后一个 id(数字)。看看聚合机制是如何工作的,我可以很好地理解为什么结果不是我想要的。这些项目按照我添加的顺序返回,然后进行聚合,以便返回我添加的最后一个。
我尝试按 id 排序,以便每个组独立排序,但这不起作用:
benchmarks=# select last(id),sorter from aggtest group by sorter order by sorter,id;
ERROR: column "aggtest.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: ...(id),sorter from aggtest group by sorter order by sorter,id;
如果我将排序标准包装在另一个聚合中,我会再次得到错误的数据:
benchmarks=# select last(id),sorter from aggtest group by sorter order by sorter,last(id);
last | sorter
------+--------
4 | 1
6 | 2
(2 rows)
除了排序器之外,按 id 分组显然也不起作用。
当然有一种更简单的方法,通过使用 max
聚合来获取每个组的最后一个(最高)ID。但是,我对 id 不太感兴趣,而是对与其关联的数据(即在同一行中)感兴趣。因此,我不会按 id 排序然后聚合,以便为每个组返回具有最高 id 的行。
实现这一目标的最佳方法是什么?
编辑:为什么按排序器分组的 max(id)
不起作用
假设以下完整表格(unsorter 代表我在表格中拥有的附加数据):
benchmarks=# select * from aggtest ;
id | sorter | unsorter
----+--------+----------
1 | 1 | 1
3 | 1 | 2
5 | 1 | 3
2 | 2 | 4
7 | 2 | 5
4 | 1 | 6
6 | 2 | 7
(7 rows)
我想检索这些行:
id | sorter | unsorter
----+--------+----------
5 | 1 | 3
7 | 2 | 5
但是,通过 max(id)
并按排序器分组,我得到:
benchmarks=# select max(id),sorter,unsorter from aggtest group by sorter;
ERROR: column "aggtest.unsorter" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: select max(id),sorter,unsorter from aggtest group by sorter;
使用 max(unsorter)
显然也不起作用:
benchmarks=# select max(id),sorter,max(unsorter) from aggtest group by sorter;
max | sorter | max
-----+--------+-----
5 | 1 | 6
7 | 2 | 7
(2 rows)
但是使用不同的(接受的答案)我得到:
benchmarks=# select distinct on (sorter) id,sorter,unsorter from aggtest order by sorter, id desc;
id | sorter | unsorter
----+--------+----------
5 | 1 | 3
7 | 2 | 5
(2 rows)
其中包含正确的附加数据。连接方法似乎也有效,但在测试数据上稍微慢一些。
最佳答案
为什么不使用窗口函数:
select id, sorter
from (
select id, sorter,
row_number() over (partition by sorter order by id desc) as rn
from aggtest
) t
where rn = 1;
或者使用 Postgres distinct on
运算符,这通常更快:
select distinct on (sorter) id, sorter
from aggtest
order by sorter, id desc
关于sql - 获取 postgresql 中有序集合的最后一个元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29032345/