zeoran
zeoran

Reputation: 115

Select top three values in each group

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

Answers (3)

cynox
cynox

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

poshest
poshest

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

Veera
Veera

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

--Quick Demo Here...

Upvotes: 22

Related Questions