SQL select语句,用于根据行的唯一值将行转换为列

时间:2013-12-02 20:02:42

标签: sql oracle11g pivot

我将以下数据放在oracle数据库中名为training的表中

id dept  usr   tt   em     sk    sal
10  2   user1  ttl1  eml2  skl1  100
10  2   user1  ttl1  eml2  skl2  200
10  2   user1  ttl1  eml2  skl3  300
10  2   user1  ttl1  eml2  skl4  400
20  3   user2  ttl3  eml4  skl1  150
30  4   user3  ttl6  eml8  skl1  100
30  4   user3  ttl6  eml8  skl2  200
30  4   user3  ttl6  eml8  skl3  300
30  4   user3  ttl6  eml8  skl4  400
30  4   user3  ttl6  eml8  skl5  150    
...
and many more rows

有没有办法用sql select语句获得以下结果?

id  dept usr    tt   em   sk1   sal1 sk2  sal2 sk3  sal3 sk4  sal4 sk5  sal5 sk6  sal6
10  2    user1  ttl1 eml2 skl1  100  skl2 200  skl3 300  skl4 300   
20  3    user2  ttl3 eml4 skl1  150
30  4    user3  ttl6 eml8 skl1  100  skl2 200  skl3 300  skl4 400  skl5 150
...

1 个答案:

答案 0 :(得分:0)

获得结果的简单方法是使用带有CASE表达式的聚合函数。我首先查询数据并使用窗口函数row_number()根据iddeptusr为数据组生成唯一序列:

select id,
  dept,
  usr,
  tt,
  em,
  max(case when seq = 1 then sk end) sk1,
  max(case when seq = 1 then sal end) sal1,
  max(case when seq = 2 then sk end) sk2,
  max(case when seq = 2 then sal end) sal2,
  max(case when seq = 3 then sk end) sk3,
  max(case when seq = 3 then sal end) sal3,
  max(case when seq = 4 then sk end) sk4,
  max(case when seq = 4 then sal end) sal4,
  max(case when seq = 5 then sk end) sk5,
  max(case when seq = 5 then sal end) sal5,
  max(case when seq = 6 then sk end) sk6,
  max(case when seq = 6 then sal end) sal6
from
(
  select id, dept, usr, tt, em, sk, sal,
    row_number() over(partition by id, dept, usr
                      order by sk) seq
  from yourtable
) d
group by id, dept, usr, tt, em;

请参阅SQL Fiddle with Demo

由于您使用的是Oracle 11g,因此您可以实现PIVOT和UNPIVOT函数来获取结果。 UNPIVOT将用于将多个sksal列转换为多行,然后您可以使用PIVOT将其转换为最终结果。语法类似于:

with cte as
(
  select id, dept, usr, tt, em, sk, 
    to_char(sal) sal,
    row_number() over(partition by id, dept, usr
                      order by sk) seq
  from yourtable
)
select 
  id, dept, usr, tt, em,
  sk1, sal1, sk2, sal2,
  sk3, sal3, sk4, sal4,
  sk5, sal5, sk6, sal6
from
(
  select id, dept, usr, tt, em, 
    lower(col)||to_char(seq) col, value
  from cte
  unpivot
  (
    value
    for col in (sk, sal)
  ) u
) d
pivot
(
  max(value)
  for col in ('sk1' as sk1, 'sal1' as sal1, 
              'sk2' as sk2, 'sal2' as sal2, 
              'sk3' as sk3, 'sal3' as sal3,
              'sk4' as sk4, 'sal4' as sal4,
              'sk5' as sk5, 'sal5' as sal5,
              'sk6' as sk6, 'sal6' as sal6)
) ;

SQL FIddle with Demo。两者都给出了结果:

| ID | DEPT |   USR |   TT |   EM |  SK1 | SAL1 |    SK2 |   SAL2 |    SK3 |   SAL3 |    SK4 |   SAL4 |    SK5 |   SAL5 |    SK6 |   SAL6 |
|----|------|-------|------|------|------|------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|
| 10 |    2 | user1 | ttl1 | eml2 | skl1 |  100 |   skl2 |    200 |   skl3 |    300 |   skl4 |    400 | (null) | (null) | (null) | (null) |
| 20 |    3 | user2 | ttl3 | eml4 | skl1 |  150 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
| 30 |    4 | user3 | ttl6 | eml8 | skl1 |  100 |   skl2 |    200 |   skl3 |    300 |   skl4 |    400 |   skl5 |    150 | (null) | (null) |