如何使用pivotsql

如何使用pivotsql,sql,oracle,pivot,unpivot,Sql,Oracle,Pivot,Unpivot,比如说, select A,B,C,D,E,YEAR FROM t1 where t1.year = 2018 UNION ALL select A,B,C,D,E,YEAR FROM t2 where t2.year = 2017 这样执行 A --- B----C----D----E----YEAR 2 --- 4----6----8----10---2018 1 --- 3----5----7----9----2017 2018 2017 A 2 1 B 4 3

比如说,

select A,B,C,D,E,YEAR
FROM t1
where t1.year = 2018
UNION ALL
select A,B,C,D,E,YEAR
FROM t2
where t2.year = 2017
这样执行

A --- B----C----D----E----YEAR
2 --- 4----6----8----10---2018
1 --- 3----5----7----9----2017
  2018  2017
A  2    1
B  4    3
C  6    5
D  8    7
E  10   9
我希望有这样的结果

A --- B----C----D----E----YEAR
2 --- 4----6----8----10---2018
1 --- 3----5----7----9----2017
  2018  2017
A  2    1
B  4    3
C  6    5
D  8    7
E  10   9
我知道我应该使用pivot,并在Google上搜索了一下,但我不知道如何编写代码来获得上述结果


谢谢

这有点棘手-取消填充和重新填充。这里有一个方法:

select col,
       max(case when year = 2018 then val end) as val_2018,
       max(case when year = 2017 then val end) as val_2017
from ((select 'A' as col, A as val, YEAR from t1 where year = 2018) union all
      (select 'B' as col, B as val, YEAR from t1 where year = 2018) union all
      (select 'C' as col, C as val, YEAR from t1 where year = 2018) union all
      (select 'D' as col, D as val, YEAR from t1 where year = 2018) union all
      (select 'E' as col, D as val, YEAR from t1 where year = 2018) union all
      (select 'A' as col, A as val, YEAR from t2 where year = 2017) union all
      (select 'B' as col, B as val, YEAR from t2 where year = 2017) union all
      (select 'C' as col, C as val, YEAR from t2 where year = 2017) union all
      (select 'D' as col, D as val, YEAR from t2 where year = 2017) union all
      (select 'E' as col, D as val, YEAR from t2 where year = 2017) 
     ) tt
group by col;

您不指定数据库,但这与数据库无关。

假设您使用的是Oracle 11.1或更高版本,则可以使用pivot和unpivot运算符。在您的问题中,数据已经以一种方式旋转,但您希望数据以另一种方式旋转;因此,您必须先取消旋转,然后按您希望的方式重新旋转。在下面的解决方案中,数据是从表中读取的,我使用WITH子句来生成测试数据,但您不需要WITH子句,您可以从SELECT开始并使用实际的表名和列名。数据通过unpivot传递,然后立即传递到pivot——您不需要子查询或类似的东西

关于列名的注意事项:不要使用year,它是一个Oracle关键字,如果不是更糟的话,您将导致混淆。在输出中,不能有任何字符,例如列名,标识符必须以字母开头。您可以使用双引号中的名称绕过这些限制;不过,这是一个非常糟糕的实践,最好只让Oracle解析器来使用,而不让我们人类使用。您将看到我调用了输入列yr和输出列y2018等等

with
  inputs ( a, b, c, d, e, yr ) as (
    select 2, 4, 6, 8, 10, 2018 from dual union all
    select 1, 3, 5, 7,  9, 2017 from dual
  )
select   col, y2018, y2017
from     inputs
unpivot  ( val for col in (a as 'A', b as 'B', c as 'C', d as 'D', e as 'E') )
pivot    ( min(val) for yr in (2018 as y2018, 2017 as y2017) )
order by col   --   if needed
;

COL      Y2018      Y2017
--- ---------- ----------
A            2          1
B            4          3
C            6          5
D            8          7
E           10          9
增加:

以下是在Oracle 11.1中引入pivot和unpivot之前的做法。取消PIVOT是通过交叉连接到一个小的辅助表来完成的,该辅助表只有一列,行数与基表中要取消PIVOT的列数相同——在这种情况下,需要取消PIVOT五列,即a、b、c、d、e,因此辅助表有五行。数据透视是通过条件聚合完成的。这两种查询都可以合并到一个查询中——除了创建helper表或内联视图之外,不需要子查询

请注意,重要的是,基表只读取一次。其他取消激励的方法效率要低得多,因为它们需要多次读取基表

select decode(lvl, 1, 'A', 2, 'B', 3, 'C', 4, 'D', 5, 'E') as col,
       max(case yr when 2018 then decode(lvl, 1, a, 2, b, 3, c, 4, d, 5, e) end) as y2018,
       max(case yr when 2017 then decode(lvl, 1, a, 2, b, 3, c, 4, d, 5, e) end) as y2017
from   inputs cross join ( select level as lvl from dual connect by level <= 5 )
group by decode(lvl, 1, 'A', 2, 'B', 3, 'C', 4, 'D', 5, 'E')
order by decode(lvl, 1, 'A', 2, 'B', 3, 'C', 4, 'D', 5, 'E')
;
这看起来比实际情况更糟;同一个decode函数调用三次,但参数完全相同,因此只计算一次,值被缓存,并在其他地方重用。它是为group by计算的,然后重新用于select和order by

要进行测试,您可以使用与上述相同的WITH子句,也可以使用实际数据


decode是Oracle专有的,但同样可以使用与decode方法基本相同的case表达式编写,只是不同的语法,它将在大多数其他数据库产品中工作。

用您正在使用的数据库标记您的问题。戈登:如果您不想使用unpivot运算符,则不应使用UNION ALL来取消提示。您应该准确地读取基表一次;交叉连接到一个小表,表中的行数与必须取消连接的列数相同。@mathguy。当我回答这个问题时,这个问题并没有被贴上甲骨文的标签。这和我说的有什么关系?没有什么要取消PIVOT,请使用交叉联接,而不是多个union all。我已经在我的答案的底部展示了如何。