如何在 Oracle SQL 中对同一行的列进行排名

How to rank columns of a same row in Oracle SQL

我在 table 中有以下行:

C1 |C2 |C3 |C4

 7 | 3 | 1 | 6

我想构建一个查询,使每一列都有一个顺序;

O1 |O2 |O3 |O4
 4 | 2 | 1 | 3

是否可以在单个查询中进行这种逐行比较?或者是构建复杂 case when 语句的唯一选择?

编辑:我试图绕过的情况:

case 
    when C1 = greatest ( C1, C2, C3, C4) then 1
    when C1 >= C2 and C1 >= C3 and C1 < C4
      or C1 >= C2 and C1 <  C3 and C1 >= C4
      or C1 <  C2 and C1 >= C3 and C1 >= C4 then 2
    when C1 >= C2 and C1 <  C3 and C1 <  C4
      or C1 <  C2 and C1 >= C3 and C1 <  C4
      or C1 <  C2 and C1 <  C3 and C1 >= C4 then 3
    when C1 = least (C1, C2, C3, C4 ) then 4 
end as O1

如果值相等,索引决定顺序:如果C2 = C3,O2 = 1,O2 = 3。

如您所见,这很容易出错。有没有办法让这个比较更优雅?

只需要在单行中进行比较,单行中的列顺序不会影响 table 中行的顺序。

编辑 2:table 中有多行,用 ID_ROW 标识。

我想你的意思是连续使用 unpivotpivot :

create table mytable(C1 int, C2 int, C3 int, C4 int );
insert into mytable values(7, 3, 1, 6);

select * from
(
select CX variable, dense_rank() over ( order by value ) value
  from mytable
unpivot (value for CX in (C1, C2, C3, C4))
)
pivot
(
 max(value) as vl for(variable) in ('C1' AS C1, 'C2' AS C2, 'C3' AS C3, 'C4' AS C4 )
);

C1_VL   C2_VL   C3_VL   C4_VL
  4       2       1       3

SQL Fiddle Demo

复杂的嵌套 case-when 不是必需的,您可以使用 "simple" case-when 和求和(虽然有点乏味)

select t.*,

     case when c1>c2 then 1 else 0 end
     + case when c1>c3 then 1 else 0 end
     + case when c1>c4 then 1 else 0 end + 1 as q1,

     case when c2>c1 then 1 else 0 end
     + case when c2>c3 then 1 else 0 end
     + case when c2>c4 then 1 else 0 end + 1 as q2,

     case when c3>c1 then 1 else 0 end
     + case when c3>c2 then 1 else 0 end
     + case when c3>c4 then 1 else 0 end + 1 as q3 ,

     case when c4>c1 then 1 else 0 end
     + case when c4>c2 then 1 else 0 end
     + case when c4>c3 then 1 else 0 end + 1 as q4 

FROM table1 t;

| c1 | c2 | c3 | c4 | q1 | q2 | q3 | q4 |
|----|----|----|----|----|----|----|----|
|  7 |  3 |  1 |  6 |  4 |  2 |  1 |  3 |
|  6 |  5 |  4 |  1 |  4 |  3 |  2 |  1 |

一种方法是逆透视数据,使用 ROW_NUMBER() 分析函数并重新透视。这种方法可能比直接处理每一行花费更长的时间,但更容易维护。您需要决定哪个目标更重要。

EDIT - 基于所需的领带处理(仍不清楚),也许 ROW_NUMBER() 应替换为 RANK() 或 DENSE_RANK();否则解决方案是相同的。 结束编辑

create table inputs ( id_row, c1, c2, c3, c4 ) as
  select 101, 7, 3, 1, 6 from dual union all
  select 102, 1, 5, 5, 2 from dual union all
  select 103, 0, 0, 0, 0 from dual union all
  select 104, 8, 3, 4, 1 from dual
;

select id_row, 
       c1_val as c1, c2_val as c2, c3_val as c3, c4_val as c4,
       c1_rn  as o1, c2_rn  as o2, c3_rn  as o3, c4_rn  as o4
from   (
         select  id_row, val, col, 
                 row_number() over 
                     (partition by id_row order by val, col) as rn
         from    inputs
         unpivot ( val for col in (c1 as 1, c2 as 2, c3 as 3, c4 as 4) )
       )
pivot  ( min(val) as val, min(rn) as rn 
         for col in (1 as c1, 2 as c2, 3 as c3, 4 as c4) )
;

  ID_ROW     C1     C2     C3     C4     O1     O2     O3     O4
-------- ------ ------ ------ ------ ------ ------ ------ ------
     101      7      3      1      6      4      2      1      3
     102      1      5      5      2      1      3      4      2
     103      0      0      0      0      1      2      3      4
     104      8      3      4      1      4      2      3      1