同时转置多个列

Transpose multiple Columns at same

我有这个:

Year   Apple   Orange 
1       100       150
2       200       250
3       300       350
2       200       250
1       100       150

我需要这个:

Fruit       1           2            3
Apple      200         400          300
Orange     300         500          350

我有选项 A 和选项 B,但它只能调换 1 个水果,除非我做一个 "Union all"。

选项A:

select 
     'Apple' as Fruit
     ,MAX(DECODE(year, '1', sum(Apple)) "1"
     ,MAX(DECODE(year, '2', sum(Apple)) "2"
from MyTable

选项 B:

select 
     * 
from (
     select 
          Apple
          ,Year 
     from MyTable
     ) 
PIVOT(sum(Apple) for year in ('1', '2', '3'))

问题:

你可以转置所有没有 "Union" 的列吗?

Oracle 设置:

CREATE TABLE table_name ( year, apple, orange ) AS
SELECT 1, 100, 150 FROM DUAL UNION ALL
SELECT 2, 200, 250 FROM DUAL UNION ALL
SELECT 3, 300, 350 FROM DUAL UNION ALL
SELECT 2, 200, 250 FROM DUAL UNION ALL
SELECT 1, 100, 150 FROM DUAL;

查询 - 逆透视然后透视:

SELECT *
FROM   (
  SELECT *
  FROM   table_name
  UNPIVOT( value FOR fruit IN ( Apple, Orange ) )
)
PIVOT ( SUM( value ) FOR year IN ( 1, 2, 3 ) );

输出:

FRUIT  1   2   3
------ --- --- ---
ORANGE 300 500 350
APPLE  200 400 300

这是动态执行的方法。

创建报表

CREATE TABLE MyTable
    (Year int, Apple int, Orange int) ;
INSERT ALL 
    INTO MyTable (Year, Apple, Orange)      VALUES (1, 100, 150)
    INTO MyTable (Year, Apple, Orange)       VALUES (2, 200, 250)
    INTO MyTable (Year, Apple, Orange)       VALUES (3, 300, 350)
    INTO MyTable (Year, Apple, Orange)       VALUES (2, 200, 250)
    INTO MyTable (Year, Apple, Orange)       VALUES (1, 100, 150)
SELECT * FROM dual;

运行 在 SQL Developer 或 SQLPlus 中(我在 SQL Developer 中试过)。 或者你可以将它封装在一个过程中,并且可以 return 结果。

SET ServerOutput ON size 100000;
variable rc refcursor;
DECLARE 
v_column_list varchar2 (2000);
v_years varchar2(2000);
BEGIN
    SELECT listagg('"' || column_name || '"', ',') within
    GROUP (ORDER BY column_id)
    INTO v_column_list
    FROM all_tab_columns
    WHERE table_name = 'MYTABLE'
        AND column_name <> 'YEAR';

    SELECT listagg(year, ',') within
    GROUP (ORDER BY year)
    INTO v_years
    FROM (
        SELECT DISTINCT year
        FROM MyTable);
--  dbms_output.put_line(' v_column_list =' || v_column_list);
--  dbms_output.put_line(' v_years =' || v_years);
    OPEN :rc FOR 
    'SELECT * FROM 
   ( SELECT *
        FROM MyTable 
          UNPIVOT ( val for fruit in ( ' || v_column_list || ' ) 
                  )
    ) 
    PIVOT ( sum ( val ) for year in ( ' || v_years || ' ) )';
END;
/

PRINT :rc

输出:

------------------------------------------------------------------------
FRUIT   1                       2                       3                      
------  ---------------------- ---------------------- ---------------------- 
ORANGE  300                     500                     350                 
APPLE   200                     400                     300