如何使用Pivot SQL

时间:2018-01-16 16:42:02

标签: 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
C  6    5
D  8    7
E  10   9

我知道我应该使用pivot,并使用Google搜索,但我无法弄清楚如何编写代码以获得如上所示的结果。

由于

2 个答案:

答案 0 :(得分:1)

假设您使用的是Oracle 11.1或更高版本,则可以使用pivotunpivot运算符。在您的问题中,数据已经以某种方式“转动”,但您希望它以另一种方式转动;所以你必须先解锁,然后按照你想要的方式重新转动。在下面的解决方案中,从表中读取数据(我使用WITH子句生成测试数据,但是您不需要WITH子句,您可以从SELECT开始并使用您的实际表和列名称)。数据通过unpivot提供,然后立即提供给pivot - 您不需要子查询或类似的任何内容。

关于列名称的注意事项:不要使用year,它是一个Oracle关键字,如果不是(更糟),你会引起混淆。在输出中,您不能拥有2018和列名等 - 标识符必须以字母开头。您可以使用双引号中的名称来解决这些限制;这是一个非常糟糕的做法,最好留给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

<强> ADDED

以下是这样做的过程(在Oracle 11.1中引入pivotunpivot之前)。 Unpivoting是通过交叉连接到一个小的帮助器表来完成的,它有一个列和多个行,就像要在基表中展开的列一样多 - 在这种情况下,五列,a, b, c, d, e需要不显示,所以帮助器表有五行。并且使用条件聚合完成了旋转。两者都可以合并为一个查询 - 不需要子查询(除了创建帮助器“表”或内联视图)。

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

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计算的,然后重新用于selectorder by。)

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

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

答案 1 :(得分:0)

这有点棘手 - 无需翻转和重新投票。这是一种方式:

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;

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