我正在尝试获取存储在数据库表中的有序集的最后一个元素。排序由表中的一列定义。该表还包含多个集合,因此我希望每个集合都有最后一个集合。
作为示例,请考虑下表:
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)
然而,使用distinct(接受的答案)我得到:
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)
其中包含正确的附加数据。连接方法似乎也有效,因为测试数据稍慢。
答案 0 :(得分:1)
为什么不使用窗口功能:
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
答案 1 :(得分:1)
你写道:
当然有一种更简单的方法,可以获得最后一个(最高)ID 每组使用最大聚合。但是,我并非如此 对id感兴趣但是与它相关的数据(即在...中) 同一行)。
此查询将为您提供与每个分拣机组的最高ID相关联的数据。
select a.* from aggtest a
join (
select max(id) max_id, sorter
from aggtest
group by sorter
) b on a.id = b.max_id and a.sorter = b.sorter
答案 2 :(得分:0)
选择不同的max(id)over(partition by sorter)id,sorter 来自2 asc的aggtest命令
返回: 5; 1 7; 2