Oracle将行分组/更改为列

时间:2011-12-09 13:18:56

标签: sql oracle

我有下表名为foo:

ID | KEY  | VAL
----------------
 1 | 47   | 97
 2 | 47   | 98
 3 | 47   | 99
 4 | 48   | 100
 5 | 48   | 101
 6 | 49   | 102

我想运行一个选择查询,结果显示如下

UNIQUE_ID        | KEY  | ID1 | VAL1 | ID2 | VAL2 | ID3 | VAL3
--------------------------------------------------------------
47_1:97_2:98_3:99|  47  | 1   |  97  | 2   |  98  |  3  | 99
48_4:100_5:101   |  48  | 4   |  100 | 5   |  101 |     |  
49_6:102         |  49  | 6   |  102 |     |      |     | 

因此,基本上所有具有相同KEY的行都会折叠为1行。每个KEY值可以有1-3行

有没有办法在sql查询中执行此操作(无需编写存储过程或脚本)?

如果没有,我也可以选择不太理想的

UNIQUE_ID        | KEY  | IDS   | VALS 
--------------------------------------------------------------
47_1:97_2:98_3:99|  47  | 1,2,3 | 97,98,99
48_4:100_5:101   |  48  | 4,5   | 100, 101 
49_6:102         |  49  | 6     | 102 

谢谢!

更新:

不幸的是,我的真实世界问题似乎比这个例子困难得多,而且我无法让任何一个例子工作:(我的查询超过120行所以它不是很容易发布。它有点像喜欢:

with v_table as (select ...), 
  v_table2 as (select foo from v_table where...), 
  v_table3 as (select foo from v_table where ...),
  ...
  v_table23 as (select foo from v_table where ...)
  select distinct (...) as "UniqueID", myKey, myVal, otherCol1, ..., otherCol18 
  from tbl1 inner join tbl2 on...
  ... 
  inner join tbl15 on ...

如果我尝试下面的任何一种方法,似乎我不能正确地进行分组操作,因为返回了所有其他数据。 例如:

with v_table as (select ...), 
  v_table2 as (select foo from v_table where...), 
  v_table3 as (select foo from v_table where ...),
  ...
  v_table23 as (select foo from v_table where ...)
  select "Unique ID",
   myKey, max(decode(id_col,1,id_col)) as id_1, max(decode(id_col,1,myVal)) as val_1,
   max(decode(id_col,2,id_col)) as id_2,max(decode(id_col,2,myVal)) as val_2,
   max(decode(id_col,3,id_col)) as id_3,max(decode(id_col,3,myVal)) as val_3
  from (
    select distinct (...) as "UniqueID", myKey, row_number() over (partition by myKey order by id) as id_col, id, myVal, otherCol1, ..., otherCol18 
    from tbl1 inner join tbl2 on...
    ... 
    inner join tbl15 on ...
  ) group by myKey;

给我错误:ORA-00979:不是GROUP BY表达式

这是因为我从内部选择中选择了UniqueID。我需要这样做以及从内部表中选择其他列。

任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:4)

查看关于 Listagg 函数的this article,这将帮助您获得逗号分隔的结果,它仅适用于11g版本。

答案 1 :(得分:2)

你可以试试这个

select key,
    max(decode(id_col,1,id_col)) as id_1,max(decode(id_col,1,val)) as val_1,
    max(decode(id_col,2,id_col)) as id_2,max(decode(id_col,2,val)) as val_2,
    max(decode(id_col,3,id_col)) as id_3,max(decode(id_col,3,val)) as val_3
from (
        select key, row_number() over (partition by key order by id) as id_col,id,val
        from your_table
    )
group by key

答案 2 :(得分:2)

作为@ O.D。建议,您可以使用LISTAGG生成不太理想的版本(例如,使用CTE生成示例数据):

with foo as (
select 1 as id, 47 as key, 97 as val from dual
union select 2,47,98 from dual
union select 3,47,99 from dual
union select 4,48,100 from dual
union select 5,48,101 from dual
union select 6,49,102 from dual
)
select key ||'_'|| listagg(id ||':' ||val, '_')
        within group (order by id) as unique_id,
    key,
    listagg(id, ',') within group (order by id) as ids,
    listagg(val, ',') within group (order by id) as vals
from foo
group by key
order by key;

UNIQUE_ID          KEY IDS                  VALS
----------------- ---- -------------------- --------------------
47_1:97_2:98_3:99   47 1,2,3                97,98,99
48_4:100_5:101      48 4,5                  100,101
49_6:102            49 6                    102

通过更多操作,您可以获得您的首选结果:

with foo as (
select 1 as id, 47 as key, 97 as val from dual
union select 2,47,98 from dual
union select 3,47,99 from dual
union select 4,48,100 from dual
union select 5,48,101 from dual
union select 6,49,102 from dual
)
select unique_id, key,
    max(id1) as id1, max(val1) as val1,
    max(id2) as id2, max(val2) as val2,
    max(id3) as id3, max(val3) as val3
from (
    select unique_id,key,
        case when r = 1 then id end as id1, case when r = 1 then val end as val1,
        case when r = 2 then id end as id2, case when r = 2 then val end as val2,
        case when r = 3 then id end as id3, case when r = 3 then val end as val3
    from (
        select key ||'_'|| listagg(id ||':' ||val, '_')
                within group (order by id) over (partition by key) as unique_id,
            key, id, val,
            row_number() over (partition by key order by id) as r
        from foo
    )
)
group by unique_id, key
order by key;

UNIQUE_ID          KEY  ID1 VAL1  ID2 VAL2  ID3 VAL3
----------------- ---- ---- ---- ---- ---- ---- ----
47_1:97_2:98_3:99   47    1   97    2   98    3   99
48_4:100_5:101      48    4  100    5  101
49_6:102            49    6  102

不禁觉得应该有更简单的方法......