简体   繁体   中英

Getting latest values from different columns based on other column

So I've a query like this

select 
  user_id,
  MAX(
    case when attribute = 'one' then newValue else 'No Update' end
  ) as one,
  MAX(
    case when attribute = 'two' then newValue else 'No Update' end
  ) as two,
  MAX(
    case when attribute = 'thre' then newValue else 'No Update' end
  ) as thre,
from table
group by user_id

This query returns result as max value for that particular attribute value in different column.

There is an updated_at column too in this table. Now instead of this, I want that the returned column should contain the latest value according to that updated_at field.

So basically the column one, two and thre should either contain latest values according to updated_at field. If no values are there, then the column should contain No Update string.

What could be the right way?

Example

user_id | attribute | newValue | updatedAt
1       | one       | null     | 2018-01-20
1       | one       | b        | 2018-01-21
1       | one       | a        | 2018-01-22
1       | two       | null     | 2018-01-23
1       | two       | null     | 2018-01-24
1       | two       | null     | 2018-01-25

So for above table the current query would return result as this coz b is the Max value for attribute=one

user_id | one | two 
    1   | b   | No Update

But I want the result of column one to be latest one according to updatedAt column like this

user_id | one | two 
    1   | a   | No Update

First use DISTINCT ON (user_id, attribute) to get the only the rows with the latest updatedAt for each attribute and then aggregate on the results:

select user_id,
       coalesce(max(case when attribute = 'one' then newvalue end), 'No Update') one,
       coalesce(max(case when attribute = 'two' then newvalue end), 'No Update') two
from (
  select distinct on (user_id, attribute) *
  from tablename
  order by user_id, attribute, updatedAt desc
) t 
group by user_id

See the demo .
Results:

> user_id | one | two      
> ------: | :-- | :--------
>       1 | a   | No Update

Postgres doesn't have first and last aggregation functions, but you can get similar functionality using arrays:

select user_id,
       coalesce((array_agg(newvalue order by updatedAt desc) filter (where attribute = 'one'))[1], 'No update') as one,
       coalesce((array_agg(newvalue order by updatedAt desc) filter (where attribute = 'two'))[1], 'No update') as two
from t 
group by user_id;

Here is a db<>fiddle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM