在Oracle中dynamic地将行切换成列
我有以下Oracle 10g表_kv:
select * from _kv ID KV ---- ----- ----- 1 name Bob 1 age 30 1 gender male 2 name Susan 2 status married
我想使用普通的SQL(而不是PL / SQL)将我的密钥变成列,以便生成的表格如下所示:
ID NAME AGE GENDER STATUS ---- ----- ----- ------ -------- 1 Bob 30 male 2 Susan married
- 查询应该有与表中唯一的
K
一样多的列(没有那么多) - 运行查询之前无法知道可能存在哪些列。
- 我试图避免运行一个初步的查询以编程方式build立最终的查询。
- 空白单元格可能是空值或空string,并不重要。
- 我使用Oracle 10g,但是11g解决scheme也可以。
当你知道什么是可调用的列时,有大量的例子,但是我找不到Oracle的通用透视解决scheme。
谢谢!
Oracle 11g提供了一个你想要的PIVOT
操作。
Oracle 11g解决scheme
select * from (select id, k, v from _kv) pivot(max(v) for k in ('name', 'age', 'gender', 'status')
(注:我没有11g的副本来testing这个,所以我没有validation它的function)
我从http://orafaq.com/wiki/PIVOT获得了这个解决scheme
编辑 – pivot xml选项(也是Oracle 11g)
显然,当你不知道所有可能需要的列标题时,也有一个pivot xml
选项。 (请参阅位于http://www.oracle.com/technetwork/articles/sql/11g-pivot-097235.html的页面底部附近的;XML TYPE部分)
select * from (select id, k, v from _kv) pivot xml (max(v) for k in (any) )
(注意:和以前一样,我没有11g的拷贝来testing,所以我没有validation它的function)
Edit2:更改了pivot
pivot xml
表中的v
,并将pivot xml
语句转换为max(v)
因为它应该像其中一个注释中提到的那样进行聚合。 我还添加了对于pivot
不可选的in
子句。 当然,不得不在in
子句中指定值,就像本题的海报所期望的那样,将会有一个完全dynamic的枢轴/交叉表查询的目标。
为了处理可能存在多个值的情况(例如v),我使用PIVOT
和LISTAGG
:
SELECT * FROM ( SELECT id, k, v FROM _kv ) PIVOT ( LISTAGG(v ,',') WITHIN GROUP (ORDER BY k) FOR k IN ('name', 'age','gender','status') ) ORDER BY id;
由于您需要dynamic值,因此在调用pivot语句之前,请使用dynamicSQL并传入在表数据上运行select所确定的值。
发生在枢轴上的任务。 下面为我在11g上testing:
select * from ( select ID, COUNTRY_NAME, TOTAL_COUNT from ONE_TABLE ) pivot( SUM(TOTAL_COUNT) for COUNTRY_NAME in ( 'Canada', 'USA', 'Mexico' ) );
首先,需要parsing使用pivot xml
dynamic数据pivot xml
。 我们有另一种方法做到这一点,将列名存储在一个variables中,并将其传入dynamicsql中,如下所示。
考虑下面的表格。
如果我们需要将YR
列中的值作为列名显示,那么我们可以使用下面的代码。
declare sqlqry clob; cols clob; begin select listagg('''' || YR || ''' as "' || YR || '"', ',') within group (order by YR) into cols from (select distinct YR from EMPLOYEE); sqlqry := ' select * from ( select * from EMPLOYEE ) pivot ( MIN(QTY) for YR in (' || cols || ') )'; execute immediate sqlqry; end; /
结果