在 Oracle 行的多列上使用透视

问题描述 投票:0回答:3

我在 Oracle 表 (

tab1
) 中有以下示例数据,我正在尝试将行转换为列。我知道如何在某一列上使用 Oracle 数据透视表。但是否可以将其应用于多个列?

样本数据:

Type  weight  height  
A     50      10  
A     60      12  
B     40      8  
C     30      15  

我的预期输出:

A-count B-count C-count A-weight B-weight C-weight A-height B-height C-height  
2       1       1       110      40       30       22       8        15  

我能做什么:

with T AS 
(select type, weight from tab1 )
select * from T
PIVOT (
count(type)
for type in (A, B, C, D,E,F)
)  

上面的查询给了我下面的结果

A B C  
2 1 1  

我可以用

count(*)
sum(weight)
替换
sum(height)
来调整身高或体重。我想要做但我做不到的事情是在一个查询中对所有三个(计数、重量和高度)进行旋转。

可以使用pivot来完成吗?

sql oracle oracle11g pivot
3个回答
52
投票

文档所示,您可以有多个聚合函数子句。所以你可以这样做:

select *
from (
  select type, weight, height from tab1
)
pivot (
  count(type) as ct, sum(weight) as wt, sum(height) as ht
  for type in ('A' as A, 'B' as B, 'C' as C)
);
A_CT A_WT A_HT B_CT B_WT B_HT C_CT C_WT C_HT
2 110 22 1 40 8 1 30 15

如果您希望按照显示的顺序列出列,请列出它们,而不是使用

select *
(通常应该避免使用,除了临时查询或内部查询):

select a_ct, b_ct, c_ct, a_wt, b_wt, c_wt, a_ht, b_ht, c_ht
from (
  select type, weight, height from tab1
)
pivot (
  count(type) as ct, sum(weight) as wt, sum(height) as ht
  for type in ('A' as A, 'B' as B, 'C' as C)
);
A_CT B_CT C_CT A_WT B_WT C_WT A_HT B_HT C_HT
2 1 1 110 40 30 22 8 15

如果这些是表中唯一的列,那么您不需要任何子查询:

select a_ct, b_ct, c_ct, a_wt, b_wt, c_wt, a_ht, b_ht, c_ht
from tab1
pivot (
  count(type) as ct, sum(weight) as wt, sum(height) as ht
  for type in ('A' as A, 'B' as B, 'C' as C)
);

...但是如果还有其他列,您将获得比预期更多的行。

小提琴


5
投票

第二种命名列的方法更好,可以解决更多问题。我有一个要求,我想汇总从 PIVOT 返回的数据,因此有了列名,我可以简单地添加 2 并在第三个中获得所需的结果 -

select a_ct, b_ct, c_ct, a_wt, b_wt, c_wt, a_ht, b_ht, c_ht, a_wt + b_wt + c_wt tot_wt
from (
  select * from (
    select * from tab1
  )
  pivot (
    count(type) as ct, sum(weight) as wt, sum(height) as ht
    for type in ('A' as A, 'B' as B, 'C' as C)
  )
);

A_CT B_CT C_CT A_WT B_WT C_WT A_HT B_HT C_HT TOT_WT
---- ---- ---- ---- ---- ---- ---- ---- ---- ------
   2    1    1  110   40   30   22    8   15 180

请注意,如果使用的 PIVOT 列之一返回 null,聚合函数(如 sum)将不会按预期运行,在这种情况下,我已使用 CASE 语句来解决它。

希望它对某人有帮助。


1
投票

Alex Poole 的回答非常棒,对我的 Oracle 查询很有帮助。 这让我很好奇,在这里我将快速指出 Oracle for Microsoft PIVOT 多列的语法比较。 在这一领域,我实际上会授予 Oracle SQL 更简单语法奖(这是我创建的一个虚构奖项)。

当需要旋转多个列时,Microsoft SQL 远没有那么简单和灵活。

  • 您必须连接原始分组字段以使其不同
  • MSFT SQL 中的列名别名需要更多手动操作;下面的代码没有别名
  • 您必须进行多次 PIVOT 调用
  • 您必须为 PIVOT 函数添加别名以避免语法错误
  • 即使考虑了所有这些因素,它仍然没有按预期分组
  • 底线,Oracle 赢得了 SQL 更简单语法奖

给定相同的数据集:

DECLARE @tblSampleData AS table (Type nvarchar(10), Weight numeric(5,2), Height numeric(5,2))

INSERT INTO @tblSampleData (Type, Weight, Height)
VALUES
('A',     50,      10) 
,('A',     60,      12) 
,('B',     40,      8 )
,('C',     30,      15)

微软 SQL:

enter image description here

select * from 
(
    select 
        *
        ,concat(Type,'1') as "Type1" 
        ,concat(Type,'2') as "Type2"
    from @tblSampleData
) AS src
pivot (
    count(Type) --as ct, sum(weight) as wt, sum(height) as ht
    for Type in ([A], [B], [C])
) AS pvt1
pivot (
    sum(weight) --as ct, sum(weight) as wt, sum(height) as ht
    for Type1 in ([A1], [B1], [C1])
) AS pvt1
pivot (
    sum(height) --as ct, sum(weight) as wt, sum(height) as ht
    for Type2 in ([A2], [B2], [C2])
) AS pvt1
© www.soinside.com 2019 - 2024. All rights reserved.