在 Oracle SQL 中按报告日期的 PIVOT 值

Posted

技术标签:

【中文标题】在 Oracle SQL 中按报告日期的 PIVOT 值【英文标题】:PIVOT for value by reported date in Oracle SQL 【发布时间】:2021-04-22 18:17:54 【问题描述】:

我正在尝试使用 pivot 来完成以下操作:

源表中的数据如下:

Company Company ID Product Code Product Unit Reporting Year Value
a 1 dd gln 2019 7
a 1 dd gln 2020 2
b 2 bb kg 2021 3

透视表中的数据应如下所示:

Company Company ID Product Code Product Unit 2019 2020 2021
a 1 dd gln 7 2
b 2 bb kg 3

我试过了,还是不行:

从源中选择 * 枢 ( 年份的最大值(值) (2019,2020,2021) );

非常感谢任何帮助。

【问题讨论】:

请edit 包含minimal reproducible example 的问题:source 表的 DDL (CREATE TABLE) 语句;示例数据的 DML (INSERT) 语句;以及错误的全文。表中列名为Reporting Year 的标题与查询为year 之间存在不匹配;其中一个是错误的,我们需要知道您如何创建表格以提供准确的解决方案。最简单的答案是您有一个错字并且使用了错误的名称,但只是说“我试过了,但它没有用”无助于调试它,我们需要更多信息。 【参考方案1】:

year 更改为reportingyear,您的代码似乎可以工作:

select * from source pivot ( max(value) for reportingyear in (2019,2020,2021) );

其中,对于样本数据:

CREATE TABLE source ( Company, CompanyID, ProductCode, ProductUnit, ReportingYear, Value ) AS
SELECT 'a', 1, 'dd', 'gln', 2019, 7 FROM DUAL UNION ALL
SELECT 'a', 1, 'dd', 'gln', 2020, 2 FROM DUAL UNION ALL
SELECT 'b', 2, 'bb', 'kg', 2021, 3 FROM DUAL

输出:

COMPANY COMPANYID PRODUCTCODE PRODUCTUNIT 2019 2020 2021
b 2 bb kg <null> <null> 3
a 1 dd gln 7 2 <null>

如果您使用带引号的标识符并且列名中有空格,那么每次引用该列时都需要使用带引号的标识符:

select * from source pivot ( max(value) for "Reporting Year" in (2019,2020,2021) );

db小提琴here

【讨论】:

【参考方案2】:

只使用条件聚合:

select Company, Company_ID, Product_Code, Product_Unit,
       sum(case when year = 2019 then value else 0 end) as val_2019,
       sum(case when year = 2020 then value else 0 end) as val_2020,
       sum(case when year = 2021 then value else 0 end) as val_2021
from source
group by Company, Company_ID, Product_Code, Product_Unit;

【讨论】:

【参考方案3】:

无需使用动态代码结构指定PIVOT 子句列表中的所有年份,假设当前表中只有这三个年份值,并传播到新的透视列以及新插入的即将到来的年份值通过创建一个存储函数,例如

CREATE OR REPLACE FUNCTION Fn_Pivot_Table RETURN SYS_REFCURSOR IS
  v_recordset SYS_REFCURSOR;
  v_sql       VARCHAR2(32767);
  v_cols      VARCHAR2(32767);   
BEGIN
  SELECT LISTAGG( ReportingYear  , ',') WITHIN GROUP ( ORDER BY ReportingYear )                 
    INTO v_cols
    FROM ( SELECT DISTINCT ReportingYear FROM source );
      
  v_sql :='SELECT * 
             FROM source
            PIVOT(
                   MAX(Value) FOR ReportingYear IN (' || v_cols ||' ) 
                  ) 
            ORDER BY CompanyID';

  OPEN v_recordset FOR v_sql;
  RETURN v_recordset;
END;
/

可以从 SQL Developer 的控制台调用

SQL> DECLARE
    result SYS_REFCURSOR;
BEGIN
   :result := Fn_Pivot_Table;
END;
/

SQL> PRINT result;

【讨论】:

【参考方案4】:

你快到了:

select * from source pivot ( max(Value) for "Reporting Year" in (2019,2020,2021) );

请注意,Oracle 不允许列名带有空格,因此应该将其中的空格替换为下划线,例如。

因此,查询将是:

select * from source pivot ( max(Value) for "Reporting_Year" in (2019,2020,2021) );

【讨论】:

以上是关于在 Oracle SQL 中按报告日期的 PIVOT 值的主要内容,如果未能解决你的问题,请参考以下文章

SQL中按日期进行查询,如何截取日期进行查询

在 Oracle SQL 中按时间间隔聚合数据

如何在 Looker 中按日期计算状态变化?

在 oracle 中按顺序更新

如何在SQL中按时间段查询数据

如何在 Oracle 中按组填写缺失的日期