Reputation: 115
following is my sample table and rows
create table com (company text,val int);
insert into com values ('com1',1),('com1',2),('com1',3),('com1',4),('com1',5);
insert into com values ('com2',11),('com2',22),('com2',33),('com2',44),('com2',55);
insert into com values ('com3',111),('com3',222),('com3',333),('com3',444),('com3',555);
I want to get the top 3 value of each company, expected output is :
company val
---------------
com1 5
com1 4
com1 3
com2 55
com2 44
com2 33
com3 555
com3 444
com3 333
Upvotes: 6
Views: 18227
Reputation: 521
You can try arrays, which are available since Postgres v9.0.
WITH com_ordered AS (SELECT * FROM com ORDER BY company,val DESC)
SELECT company,unnest((array_agg(val))[0:3])
FROM com_ordered GROUP BY company;
Upvotes: 1
Reputation: 4237
Since v9.3 you can do a lateral join
select distinct com_outer.company, com_top.val from com com_outer
join lateral (
select * from com com_inner
where com_inner.company = com_outer.company
order by com_inner.val desc
limit 3
) com_top on true
order by com_outer.company;
It might be faster but, of course, you should test performance specifically on your data and use case.
Upvotes: 6
Reputation: 3492
Try This:
SELECT company, val FROM
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY
company order by val DESC) AS Row_ID FROM com
) AS A
WHERE Row_ID < 4 ORDER BY company
Upvotes: 22