简体   繁体   中英

how to get the column name of the greatest value by using greatest function postgresql?

I have four columns in my table which are col1,col2,col3,col4. I can find the greatest value by using

select greatest(col1,col2,col3,col4) from mytable;

But I need to know the column name of the greatest value.

With CASE :

select 
  case greatest(col1,col2,col3,col4) 
    when col1 then 'col1'
    when col2 then 'col2'
    when col3 then 'col3'
    when col4 then 'col4'
    else null
  end greatestcolumnname
from mytable;

The other answers are good and I definitely agree with Gordon that this smells of a data model issue. However, you can (ab)use jsonb to do this without having to retype the names of all of your columns, if you have a unique key in your table.

create table test (id int, col1 int, col2 int, col3 int);
insert into test values (1, 1, 2, 3), (2, 6, 5, 4), (3, 7, 9, 8);

select distinct on (id) 
  id, 
  col, 
  val 
from (
    select id, 
           col, 
           val 
    from test 
    join lateral to_jsonb(test) s1(js) on true 
    join lateral jsonb_each(js) s2(col, val) on true
) sub where col != 'id' 
order by id, val desc;
 id | col  | val
----+------+-----
  1 | col3 | 3
  2 | col1 | 6
  3 | col2 | 9
(3 rows)

Basically, create jsonb for each row, which will be something like {"id": 1, "col1": 1, "col2": 2, "col3": 3} and then split it out into keys and values using jsonb_each. The result would be something like this:

 id | col  | val
----+------+-----
  1 | id   | 1
  1 | col1 | 1
  1 | col2 | 2
  1 | col3 | 3
  2 | id   | 2
  2 | col1 | 6
  2 | col2 | 5
  2 | col3 | 4
...

From there, remove the id rows and find the greatest val per id using distinct on.

You can use the same technique on any table, you would just have to change the name of the id column, if it's not id. Here's another example:

create table test2 (id int, t1 timestamp, t2 timestamp);
insert into test2 values (1, '2019-02-01T00:00:00', '2019-01-01T00:00:00');

select distinct on (id)
  id,
  col,
  val
from (
    select id,
           col,
           val
    from test2
    join lateral to_jsonb(test2) s1(js) on true
    join lateral jsonb_each(js) s2(col, val) on true
) sub where col != 'id'
order by id, val desc;
 id | col |          val
----+-----+-----------------------
  1 | t1  | "2019-02-01T00:00:00"
(1 row)

You can use;

 select case greatest(col1, col2, col3, col4)
          when col1 then
           'col1' || '=' || col1
          when col2 then
           'col2' || '=' || col2
          when col3 then
           'col3' || '=' || col3
          when col4 then
           'col4' || '=' || col4
        end as greatest_value
   from (select max(col1) as col1,
                max(col2) as col2,
                max(col3) as col3,
                max(col4) as col4
           from mytable)

You can use a lateral join:

select v.*
from t join lateral
     (select v.*
      from (values (col1, 'col1'), (col2, 'col2), (col3, 'col3'), (col4, 'col4)
           ) v(val, colname)
      order by col desc
      fetch first 1 row only
     ) v;

The fact that you want to do this suggests that you have a problem with your data model. You probably want another table, with each column value in a row.

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