在 Oracle 中使用动态列进行透视
Pivot with Dynamic Columns in Oracle
我是新的 oracle 数据库我有一个 table 如下所示
ID Passengers Age Eligible
123456 Ben 65 Yes
123456 Mary 58 Yes
123458 Stephanie 37 Yes
123458 Aaron 32 Yes
123458 Caroline 18 No
我想获得动态列名称为 Age1、Age2、Age3 等的结果,如下所示
ID Age1 Age2 Age3
123456 65 58 NULL
123458 37 32 18
可以在 SQL Server
中使用 STUFF 和 Dynamic Pivot 来实现,但我不知道如何在 Oracle
中实现
任何人都可以指导我如何在 Oracle
中动态地做到这一点
存储函数中的 SYS_REFCURSOR
( 例如 PL/SQL 使用而不是直接使用 SQL )可能会被用来获取动态生成的结果集(例如 Dynamic Pivot)。在这种情况下,会生成条件聚合的字符串:
CREATE OR REPLACE FUNCTION get_passengers_rs RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_str VARCHAR2(32767);
BEGIN
SELECT LISTAGG('MAX(CASE WHEN rn = '||lvl||' THEN age||''(''||passengers||'')'' END)
AS "Age'||lvl||'"' ,',') WITHIN GROUP (ORDER BY 0)
INTO v_str
FROM ( SELECT level AS lvl
FROM dual
CONNECT BY level <= (SELECT MAX(COUNT(*)) FROM t GROUP BY ID ) ) t;
v_sql :=
'SELECT ID, '|| v_str ||'
FROM
(
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY 0) AS rn
FROM t
)
GROUP BY ID';
OPEN v_recordset FOR v_sql;
RETURN v_recordset;
END;
我还加上了乘客的名字,以便很好的区分每一个数据
然后运行下面的代码:
VAR rc REFCURSOR
EXEC :rc := get_passengers_rs;
PRINT rc
来自 SQL 开发人员的命令行,以便查看预期的结果集。
以上代码为当前存在的数据
生成这个SQL字符串(v_sql)
SELECT ID, MAX(CASE WHEN rn = 1 THEN age||'('||passengers||')' END) AS "Age1",
MAX(CASE WHEN rn = 2 THEN age||'('||passengers||')' END) AS "Age2",
MAX(CASE WHEN rn = 3 THEN age||'('||passengers||')' END) AS "Age3"
FROM
(
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY 0) AS rn
FROM t
)
GROUP BY ID
产生
ID Age1 Age2 Age3
123456 58(Marie) 65(Ben)
123458 32(Aaron) 18(Caroline) 37(Stephanie)
作为结果集。
我是新的 oracle 数据库我有一个 table 如下所示
ID Passengers Age Eligible
123456 Ben 65 Yes
123456 Mary 58 Yes
123458 Stephanie 37 Yes
123458 Aaron 32 Yes
123458 Caroline 18 No
我想获得动态列名称为 Age1、Age2、Age3 等的结果,如下所示
ID Age1 Age2 Age3
123456 65 58 NULL
123458 37 32 18
可以在 SQL Server
中使用 STUFF 和 Dynamic Pivot 来实现,但我不知道如何在 Oracle
任何人都可以指导我如何在 Oracle
SYS_REFCURSOR
( 例如 PL/SQL 使用而不是直接使用 SQL )可能会被用来获取动态生成的结果集(例如 Dynamic Pivot)。在这种情况下,会生成条件聚合的字符串:
CREATE OR REPLACE FUNCTION get_passengers_rs RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_str VARCHAR2(32767);
BEGIN
SELECT LISTAGG('MAX(CASE WHEN rn = '||lvl||' THEN age||''(''||passengers||'')'' END)
AS "Age'||lvl||'"' ,',') WITHIN GROUP (ORDER BY 0)
INTO v_str
FROM ( SELECT level AS lvl
FROM dual
CONNECT BY level <= (SELECT MAX(COUNT(*)) FROM t GROUP BY ID ) ) t;
v_sql :=
'SELECT ID, '|| v_str ||'
FROM
(
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY 0) AS rn
FROM t
)
GROUP BY ID';
OPEN v_recordset FOR v_sql;
RETURN v_recordset;
END;
我还加上了乘客的名字,以便很好的区分每一个数据
然后运行下面的代码:
VAR rc REFCURSOR
EXEC :rc := get_passengers_rs;
PRINT rc
来自 SQL 开发人员的命令行,以便查看预期的结果集。
以上代码为当前存在的数据
生成这个SQL字符串(v_sql)SELECT ID, MAX(CASE WHEN rn = 1 THEN age||'('||passengers||')' END) AS "Age1",
MAX(CASE WHEN rn = 2 THEN age||'('||passengers||')' END) AS "Age2",
MAX(CASE WHEN rn = 3 THEN age||'('||passengers||')' END) AS "Age3"
FROM
(
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY 0) AS rn
FROM t
)
GROUP BY ID
产生
ID Age1 Age2 Age3
123456 58(Marie) 65(Ben)
123458 32(Aaron) 18(Caroline) 37(Stephanie)
作为结果集。