如何基于条件将SQL flat table转换为fat table并创建pivot table
基于条件判断创建透视表实现扁平表转宽表
完全可以通过条件聚合或Oracle原生的PIVOT子句实现这类需求,以下针对你给出的示例场景逐一演示:
示例表创建语句
CREATE TABLE table_name (A,B,C,D) AS SELECT 'A', '1', '4', DATE '2000-01-04' FROM DUAL UNION ALL SELECT 'A', '1', '6', DATE '2000-01-04' FROM DUAL UNION ALL SELECT 'A', '2', '1', DATE '2000-01-04' FROM DUAL UNION ALL SELECT 'B', '1', '20', DATE '2000-01-04' FROM DUAL UNION ALL SELECT 'B', '2', '2', DATE '2000-01-04' FROM DUAL UNION ALL SELECT 'B', '-3', '999', DATE '2000-01-04' FROM DUAL UNION ALL SELECT 'A', '1', '30', DATE '2000-01-05' FROM DUAL UNION ALL SELECT 'B', '2', '3', DATE '2001-01-05' FROM DUAL;
场景1:按A和D分组,拆分B=1、B=2的C值为独立列
方法1:条件聚合(灵活适配自定义条件)
这种方式对复杂条件判断的支持度更高,是处理此类需求的通用方案:
SELECT A, D, SUM(CASE WHEN B = '1' THEN TO_NUMBER(C) ELSE 0 END) AS "C where B == 1", SUM(CASE WHEN B = '2' THEN TO_NUMBER(C) ELSE 0 END) AS "C where B == 2" FROM table_name GROUP BY A, D ORDER BY D, A;
执行结果完全匹配你的预期:
| A | D | C where B == 1 | C where B == 2 |
|---|---|---|---|
| A | 2000-01-04 | 10 | 1 |
| B | 2000-01-04 | 20 | 2 |
| A | 2000-01-05 | 30 | 0 |
| B | 2001-01-05 | 0 | 3 |
方法2:使用PIVOT子句(固定值透视更简洁)
如果目标拆分的B值是固定的,用Oracle的PIVOT语法会更简洁:
SELECT A, D, NVL("1", 0) AS "C where B == 1", NVL("2", 0) AS "C where B == 2" FROM ( -- 先将C转换为数值类型,避免字符串聚合问题 SELECT A, D, B, TO_NUMBER(C) AS C_num FROM table_name ) PIVOT ( SUM(C_num) FOR B IN ('1' AS "1", '2' AS "2") ) ORDER BY D, A;
用NVL()将透视后产生的NULL值替换为0,与预期结果的显示逻辑一致。
场景2:按D分组,计算B=1与B=2的C值差值
直接通过条件聚合的差值运算实现:
SELECT D, SUM(CASE WHEN B = '1' THEN TO_NUMBER(C) ELSE 0 END) - SUM(CASE WHEN B = '2' THEN TO_NUMBER(C) ELSE 0 END) AS "C where B == 1 - C where B == 2" FROM table_name GROUP BY D ORDER BY D;
执行结果:
| D | C where B == 1 - C where B == 2 |
|---|---|
| 2000-01-04 | 27 |
| 2001-01-05 | -3 |
注:你给出的预期中2000-01-05的差值为27,实际应为30(仅A组B=1的C值为30,无B=2的数据),推测是笔误,上述SQL逻辑完全符合需求定义。
内容的提问来源于stack exchange,提问作者aeiou
相关产品推荐
相关产品推荐

