2

Let's suppose we have a simple table users:

id  | name | company |  other columns.......
----+------+---------+-------------------------
 1  | A    | A1
 2  | A    | A2
 3  | B    | B1
 4  | C    | C1
 5  | C    | C2
 6  | C    | C3
 ....

I want to group by name, and chose the latest value for id and company. The result I expect is three column table:

id  | name | company |
----+------+---------+
 2  | A    | A2
 3  | B    | B1
 6  | C    | C3
 ....

I am trying to use GROUP_BY, but don't know how to include company column:

SELECT
  max(id),
  name,
  ? # I don't know how to include company
FROM users
GROUP_BY name

Does anyone have better idea?

1 Answer 1

5

Use distinct on:

select distinct on (name) u.*
from users u
order by name, id desc;

distinct on is a very convenient Postgres extension. It returns the first row from a group of rows. The "grouping" is based on the columns after distinct on. The ordering is based on the order by clause.

There are two other common ways to address this. One method uses window functions:

select u.*
from (select u.*,
             row_number() over (partition by name order by id desc) as seqnum
      from users u
     ) u
where seqnum = 1;

Or a correlated subquery:

select u.*
from users u
where u.id = (select max(u2.id) from users u2 where u2.name -= u.name);

There is even a "clever" way of doing this using group by. Postgres doesn't have a "first" or "last" aggregation function. But you can use arrays:

select name, max(id),
       (array_agg(company order by id desc))[1] as country
from users u
group by name;
Sign up to request clarification or add additional context in comments.

1 Comment

Incredible answer! Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.