【问题标题】:Oracle SQL pivot queryOracle SQL 数据透视查询
【发布时间】:2011-06-18 00:32:50
【问题描述】:

我的表格中有如下数据:

MONTH VALUE

1     100
2     200
3     300
4     400
5     500
6     600

我想写一个 SQL 查询,结果如下:

MONTH_JAN MONTH_FEB MONTH_MAR MONTH_APR MONTH_MAY MONTH_JUN
100       200       300       400       500       600

【问题讨论】:

    标签: sql oracle pivot


    【解决方案1】:

    Dynamic Pivot 适用于 Oracle 11g+

    在 Oracle 的 SQL 中没有直接的动态透视方法,除非它返回 XML 类型的结果。

    对于non-XML 结果PL/SQL 可以通过创建SYS_REFCURSOR 返回类型的函数来使用

    • 带有PIVOT子句

      CREATE OR REPLACE FUNCTION Get_Month_Values RETURN SYS_REFCURSOR IS
         v_recordset SYS_REFCURSOR;
         v_sql       VARCHAR2(32767);
         v_cols      VARCHAR2(32767);
      BEGIN
         SELECT LISTAGG( ''''||month||''' AS "MONTH_'||TO_CHAR( TO_DATE(month,'mm') ,'MON')||'"' , ',' )
                        WITHIN GROUP ( ORDER BY month )
           INTO v_cols
           FROM tab;
      
         v_sql :='SELECT *
                    FROM tab t
                   PIVOT
                   (
                    MAX(value) FOR month IN ( '|| v_cols ||' )
                   )';
      
         OPEN v_recordset FOR v_sql;
         DBMS_OUTPUT.PUT_LINE(v_sql);
         RETURN v_recordset;
      END;
      /
      
    • 使用条件聚合

      CREATE OR REPLACE FUNCTION Get_Month_Values RETURN SYS_REFCURSOR IS
         v_recordset SYS_REFCURSOR;
         v_sql       VARCHAR2(32767);
         v_cols      VARCHAR2(32767);
      BEGIN
         SELECT LISTAGG('MAX( CASE WHEN month = '''||month||''' THEN '||value||' END ) AS "MONTH_'||TO_CHAR( TO_DATE(month,'mm') ,'MON')||'"' , ',' )
                        WITHIN GROUP ( ORDER BY month )                 
           INTO v_cols
           FROM tab;
      
         v_sql :='SELECT '|| v_cols ||' FROM tab';
      
         OPEN v_recordset FOR v_sql;
         DBMS_OUTPUT.PUT_LINE(v_sql);
         RETURN v_recordset;
      END;
      /
      

    然后函数可以调用为

    VAR rc REFCURSOR
    EXEC :rc := Get_Month_Values;
    PRINT rc
    

    来自 SQL Developer 的命令行

    Demo

    【讨论】:

      【解决方案2】:

      Oracle 11g 及以上

      从 Oracle 11g 开始,您现在可以使用 PIVOT 运算符来实现该结果:

      create table tq84_pivot (
        month number,
        value number
      );
      
      insert into tq84_pivot values(1, 100);
      insert into tq84_pivot values(2, 200);
      insert into tq84_pivot values(3, 300);
      insert into tq84_pivot values(4, 400);
      insert into tq84_pivot values(5, 500);
      insert into tq84_pivot values(6, 600);
      --
      insert into tq84_pivot values(1, 400);
      insert into tq84_pivot values(2, 350);
      insert into tq84_pivot values(4, 150);
      
      select 
        *
      from
        tq84_pivot
      pivot (
         sum (value) as sum_value for
           (month) in (1 as month_jan,
                       2 as month_feb,
                       3 as month_mar,
                       4 as month_apr,
                       5 as month_mai,
                       6 as month_jun,
                       7 as month_jul,
                       8 as month_aug,
                       9 as month_sep,
                      10 as month_oct,
                      11 as month_nov,
                      12 as month_dec)
      );
      

      【讨论】:

        【解决方案3】:

        Oracle 9i+ 支持:

        SELECT SUM(CASE WHEN t.month = 1 THEN t.value ELSE 0 END) AS JAN,
               SUM(CASE WHEN t.month = 2 THEN t.value ELSE 0 END) AS FEB,
               SUM(CASE WHEN t.month = 3 THEN t.value ELSE 0 END) AS MAR,
               SUM(CASE WHEN t.month = 4 THEN t.value ELSE 0 END) AS APR,
               SUM(CASE WHEN t.month = 5 THEN t.value ELSE 0 END) AS MAY,
               SUM(CASE WHEN t.month = 6 THEN t.value ELSE 0 END) AS JUN
          FROM YOUR_TABLE t
        

        您只列出了两列——这样的内容可能应该按年份分组。

        有 ANSI PIVOT(和 UNPIVOT)语法,但 Oracle 直到 11g 才支持它。在 9i 之前,您必须将 CASE 语句替换为 Oracle 特定的 DECODE。

        【讨论】:

          猜你喜欢
          • 2021-06-29
          • 2016-06-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-11-05
          • 1970-01-01
          相关资源
          最近更新 更多