使用带多个UNION的PIVOT实现Oracle数据行列转置报错问询
问题原因
- ORA-01748报错的核心原因是你使用了带空格的非标准列别名
"AIR FARE",在Oracle中如果要引用这类别名必须严格包裹双引号且完全匹配大小写,否则系统无法识别为合法的简单列名。 - 另外你的写法冗余度过高,大量重复的子查询+UNION逻辑不仅性能差,也容易出现列匹配、别名冲突等问题,同时你逻辑上混淆了行转列、列转行的适用场景,没有正确使用Oracle的PIVOT/UNPIVOT语法。
优化后实现方案
你需要的效果可以通过先生成日期序列查询基础金额,再做PIVOT行转列实现,代码如下:
WITH base_data AS ( -- 基础数据查询,一次关联所有表,用CONNECT BY生成一周6天的日期偏移,无需重复UNION SELECT TO_CHAR(TRUNC(exr.expense_report_date, 'D') + offset.dt, 'DD-Mon') AS WEEK_DATE, eet.name AS Expense_Category, NVL(ee.REIMBURSABLE_AMOUNT, 0) AS AMOUNT FROM exm_expense_reports exr CROSS JOIN (SELECT LEVEL - 1 AS dt FROM DUAL CONNECT BY LEVEL <= 6) offset LEFT JOIN exm_expenses ee ON exr.expense_report_id = ee.expense_report_id AND TO_CHAR(ee.END_DATE, 'MM/DD') = TO_CHAR(TRUNC(exr.expense_report_date, 'D') + offset.dt, 'MM/DD') LEFT JOIN exm_expense_types eet ON ee.EXPENSE_TYPE_ID = eet.EXPENSE_TYPE_ID AND eet.name IN ('Hotel', 'Air Fare') WHERE exr.EXPENSE_REPORT_NUM = 'EXP000009057987' ) -- PIVOT行转列,把日期值转为表头列 SELECT * FROM base_data PIVOT ( SUM(AMOUNT) -- 同类别同日期金额唯一,用SUM/MAX/MIN均可 FOR WEEK_DATE IN ( '22-Aug' AS "22-Aug", '23-Aug' AS "23-Aug", '24-Aug' AS "24-Aug", '25-Aug' AS "25-Aug", '26-Aug' AS "26-Aug" ) ) ORDER BY Expense_Category;
补充说明
- 如果你的报表日期是动态的,不需要写死IN列表中的值,可以使用Oracle动态SQL拼接生成查询语句。
- 原写法中的UNION会自动去重,若要保留全部数据请改用UNION ALL,避免不必要的性能损耗和数据异常。
内容的提问来源于stack exchange,提问作者Adam Wieland
相关产品推荐
相关产品推荐

