Oracle 组和数据透视 - Oracle 中的动态数据透视
Posted
技术标签:
【中文标题】Oracle 组和数据透视 - Oracle 中的动态数据透视【英文标题】:Oracle Group and Pivot - Dynamic Pivot in Oracle 【发布时间】:2021-02-26 07:36:22 【问题描述】:我有一张这样的桌子:
+-----+------+------------+
| SN | CASE | CASE_VALUE |
+-----+------+------------+
| A | AA | 1 |
| A | AB | 5 |
| A | AC | 3 |
| A | AD | 4 |
| B | BA | 5 |
| B | BB | 7 |
| B | BC | 5 |
| B | BD | 1 |
+-----+------+------------+
不知道有没有办法获得
+-----+--------+--------------+--------+--------------+--------+--------------+--------+--------------+
| SN | CASE_1 | CASE_1_VALUE | CASE_2 | CASE_2_VALUE | CASE_3 | CASE_3_VALUE | CASE_4 | CASE_4_VALUE |
+-----+--------+--------------+--------+--------------+--------+--------------+--------+--------------+
| A | AA | 1 | AB | 5 | AC | 3 | AD | 4 |
| B | BA | 5 | BB | 7 | BC | 5 | BD | 1 |
+-----+--------+--------------+--------+--------------+--------+--------------+--------+--------------+
这四种情况不需要顺序
28/02/2021 编辑
如果案例名称之间没有顺序? 喜欢吹
+-----+------+------------+
| SN | CASE | CASE_VALUE |
+-----+------+------------+
| A | AB | 1 |
| A | CD | 5 |
| A | IJ | 3 |
| A | GH | 4 |
| B | OP | 5 |
| B | EF | 7 |
| B | MN | 5 |
| B | KJ | 1 |
+-----+------+------------+
【问题讨论】:
【参考方案1】:一种选择是使用条件聚合来根据需要进行旋转,例如
SELECT sn,
MAX(CASE WHEN SUBSTR(case,2,1) = 'A' THEN case END) AS case_1,
MAX(CASE WHEN SUBSTR(case,2,1) = 'A' THEN case_value END) AS case_1_value,
MAX(CASE WHEN SUBSTR(case,2,1) = 'B' THEN case END) AS case_2,
MAX(CASE WHEN SUBSTR(case,2,1) = 'B' THEN case_value END) AS case_2_value,
MAX(CASE WHEN SUBSTR(case,2,1) = 'C' THEN case END) AS case_3,
MAX(CASE WHEN SUBSTR(case,2,1) = 'C' THEN case_value END) AS case_3_value,
MAX(CASE WHEN SUBSTR(case,2,1) = 'D' THEN case END) AS case_4,
MAX(CASE WHEN SUBSTR(case,2,1) = 'D' THEN case_value END) AS case_4_value
FROM t
GROUP BY sn
Demo
在上述情况下,枢轴是静态的。您可以创建一个返回SYS_REFCURSOR
类型的函数,如下所示,以获得动态枢轴
CREATE OR REPLACE FUNCTION Get_Pivoted_Cols RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG( 'MAX(CASE WHEN SUBSTR(case,2,1) = '''||cs||''' THEN case END ) AS "case_'||rn||'",
MAX(CASE WHEN SUBSTR(case,2,1) = '''||cs||''' THEN case_value END ) AS "case_'||rn||'_value"', ',')
WITHIN GROUP ( ORDER BY rn )
INTO v_cols
FROM ( SELECT DISTINCT SUBSTR(case,2,1) AS cs, ROW_NUMBER() OVER (PARTITION BY sn ORDER BY case) AS rn
FROM t );
v_sql :='SELECT sn,'|| v_cols ||' FROM t GROUP BY sn';
OPEN v_recordset FOR v_sql;
RETURN v_recordset;
END;
/
并从 SQL Developer 的命令行调用以查看结果集
VAR rc REFCURSOR
EXEC :rc := Get_Pivoted_Cols;
PRINT rc
【讨论】:
【参考方案2】:您需要旋转行,然后使用解码功能来映射您的输出,如下所示。 (希望 CASE 不是你专栏的真名)。
with your_data (SN, "CASE", CASE_VALUE ) as (
select 'A', 'AA', 1 from dual union all
select 'A', 'AB', 5 from dual union all
select 'A', 'AC', 3 from dual union all
select 'A', 'AD', 4 from dual union all
select 'B', 'BA', 5 from dual union all
select 'B', 'BB', 7 from dual union all
select 'B', 'BC', 5 from dual union all
select 'B', 'BD', 1 from dual
)
select SN
, decode(SN, 'A', CASE_1, CASE_5)CASE_1
, decode(SN, 'A', CASE_1_VALUE, CASE_5_VALUE)CASE_1_VALUE
, decode(SN, 'A', CASE_2, CASE_6)CASE_2
, decode(SN, 'A', CASE_2_VALUE, CASE_6_VALUE)CASE_2_VALUE
, decode(SN, 'A', CASE_3, CASE_7)CASE_3
, decode(SN, 'A', CASE_3_VALUE, CASE_7_VALUE)CASE_3_VALUE
, decode(SN, 'A', CASE_4, CASE_8)CASE_4
, decode(SN, 'A', CASE_4_VALUE, CASE_8_VALUE)CASE_4_VALUE
from your_data t
pivot (
max(case_value) as value, max("CASE") FOR "CASE" in (
'AA' CASE_1
,'AB' CASE_2
,'AC' CASE_3
,'AD' CASE_4
,'BA' CASE_5
,'BB' CASE_6
,'BC' CASE_7
,'BD' CASE_8
)
)
;
【讨论】:
【参考方案3】:我能得到的最接近,假设(根据您的数据)case
中的第一个字符将始终与 sn
匹配,我们可以以第二个字符为轴
select *
from (
select
data.*
, substr(case, 2, 1) case_t
from data
)
pivot (
max(case) type
, max(case_value) value
for case_t in (
'A' case_1
, 'B' case_2
, 'C' case_3
, 'D' case_4
)
)
【讨论】:
以上是关于Oracle 组和数据透视 - Oracle 中的动态数据透视的主要内容,如果未能解决你的问题,请参考以下文章