适用于超过三列的更通用的解决方案是将列取消旋转到单独的行中,计算出值的顺序,然后将它们旋转回列中。从 11g 开始,您可以使用
select * from your_table
unpivot (sal for month in (sal_jan as 'Jan', sal_feb as 'Feb', sal_mar as 'Mar'));
给你:
EMP_ID MONTH SAL
---------- ----- ----------
1 Jan 10000
1 Feb 15000
1 Mar 8000
2 Jan 20000
2 Feb 2000
2 Mar 10000
3 Jan 50000
3 Feb 60000
3 Mar 40000
您并不真正关心月份名称。然后按工资值添加行号伪列顺序:
select t.*, row_number() over (partition by emp_id order by sal) as rn
from your_table
unpivot (sal for month in (sal_jan as 'Jan', sal_feb as 'Feb', sal_mar as 'Mar')) t;
然后将其转回:
select * from (
select t.emp_id, t.sal,
row_number() over (partition by emp_id order by sal) as rn
from your_table
unpivot (sal for month in (sal_jan as 'Jan', sal_feb as 'Feb', sal_mar as 'Mar')) t
)
pivot (max(sal) as sal for (rn) in (1 as "1", 2 as "2", 3 as "3"))
order by emp_id;
EMP_ID 1_SAL 2_SAL 3_SAL
---------- ---------- ---------- ----------
1 8000 10000 15000
2 2000 10000 20000
3 40000 50000 60000
SQL Fiddle demo。这很容易扩展到更多列,只需将值对添加到 pivot 和 unpivot 部分的 in 子句。
如果您使用的是较早的版本 - 在您使用 11g 和 10g 标记问题时不清楚 - 您必须手动取消旋转和旋转,这有点冗长;取消透视:
with unpivot_data as (
select level as unpivot_rn from dual connect by level <= 3
)
select t.emp_id,
case ud.unpivot_rn
when 1 then t.sal_jan
when 2 then t.sal_feb
when 3 then t.sal_mar
end as sal
from t42 t
cross join unpivot_data ud;
... 其中connect by 子句中的行数和when 子句中的case 数是您拥有的列数;然后根据工资添加行号:
with unpivot_data as (
select level as unpivot_rn from dual connect by level <= 3
),
tmp_data as (
select t.emp_id,
case ud.unpivot_rn
when 1 then t.sal_jan
when 2 then t.sal_feb
when 3 then t.sal_mar
end as sal
from t42 t
cross join unpivot_data ud
)
select td.emp_id, td.sal,
row_number() over (partition by td.emp_id order by td.sal) as rn
from tmp_data td;
然后使用 max(case ...) 和 group by 转为老式方式:
with unpivot_data as (
select level as unpivot_rn from dual connect by level <= 3
),
tmp_data as (
select t.emp_id,
case ud.unpivot_rn
when 1 then t.sal_jan
when 2 then t.sal_feb
when 3 then t.sal_mar
end as sal
from your_table t
cross join unpivot_data ud
),
tmp_with_rn as (
select td.emp_id, td.sal,
row_number() over (partition by td.emp_id order by td.sal) as rn
from tmp_data td
)
select twr.emp_id,
max(case when twr.rn = 1 then twr.sal end) as month_1,
max(case when twr.rn = 2 then twr.sal end) as month_2,
max(case when twr.rn = 3 then twr.sal end) as month_3
from tmp_with_rn twr
group by twr.emp_id
order by emp_id;
EMP_ID MONTH_1 MONTH_2 MONTH_3
---------- ---------- ---------- ----------
1 8000 10000 15000
2 2000 10000 20000
3 40000 50000 60000
SQL Fiddle demo。现在,如果列数增加,您需要更改三个位置,但操作起来仍然相当简单。