在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),我使用PIVOTLISTAGG

 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 xmldynamic数据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; / 

结果

在这里输入图像描述