【问题标题】:T-SQL Query that does pivot but not aggregate进行透视但不聚合的 T-SQL 查询
【发布时间】:2013-01-24 16:27:45
【问题描述】:

您好,我有以下数据表

Class | Member | Value
----------------------
c1    | m1     | 10
c1    | m2     | 20
c1    | list   | 30
c1    | list   | 40
c1    | list   | 50
c2    | m1     | 60
c2    | m2     | 70
c2    | list   | 80

并希望将数据转换为这种形式

Class | Member 1 | Member 2 | List
----------------------------------
c1    | 10       | 20       | 30
c1    | 10       | 20       | 40
c1    | 10       | 20       | 50
c2    | 60       | 70       | 80

使用 max 作为聚合函数的正常枢轴会给我

Class | Member 1 | Member 2 | List
----------------------------------
c1    | 10       | 20       | 50
c2    | 60       | 70       | 80

但我希望列出任何类的每个 List 值。

不是通过编写充满 CASE 的 SQL 查询来寻找替代方案,例如 CASE Member WHEN 'm1' then Value, CASE Member WHEN 'm2' then Value, ... 为了实现我想要的,我想知道是否有任何是否有机会使用 pivot 并进行一些调整以使其适用于我的任务?

数据库是 SQL 2008 R2

谢谢

【问题讨论】:

  • 对于每个 Class 值,是否只有一行(并且恰好是一行)m1m2
  • 是的,成员固定为 m1, m2, ..., m99 和 list。使用 PIVOT 可以帮助我不要为每个案例编写 100 个 CASE 或 JOIN。

标签: sql tsql pivot


【解决方案1】:

没有。 PIVOT 是围绕 CASE 表达式进行聚合的有效语法糖。如果糖不起作用,你需要回到较长的形式。

PIVOT 的语法在FROM 子句中有完整描述:

<pivoted_table> ::=
    table_source PIVOT <pivot_clause> [ AS ] table_alias

<pivot_clause> ::=
        ( aggregate_function ( value_column [ [ , ]...n ]) 
        FOR pivot_column 
        IN ( <column_list> ) 
    ) 

请注意,必须提供aggregate_function。 SQL Server 中的所有聚合函数都对任意数量的输入值进行操作并生成单个输出值。没有聚合可以产生多个输出值,正如您在此处所需要的那样。


这给出了您要求的结果,但确实依赖于每个 Class 值,m1m2 中的每一个只有一行:

declare @t table (Class char(2) not null,Member varchar(4) not null,Value int not null)
insert into @t(Class,Member,Value) values
('c1','m1',10),
('c1','m2',20),
('c1','list',30),
('c1','list',40),
('c1','list',50),
('c2','m1',60),
('c2','m2',70),
('c2','list',80)

select l.Class,m1.Value as m1,m2.Value as m2,l.Value as list
from
    @t l
        inner join
    @t m1
        on
            l.Class = m1.Class and
            m1.Member = 'm1'
        inner join
    @t m2
        on
            l.Class = m2.Class and
            m2.Member = 'm2'where
l.Member='list'

结果:

Class m1          m2          list
----- ----------- ----------- -----------
c1    10          20          30
c1    10          20          40
c1    10          20          50
c2    60          70          80

如果m1m2 多行,并且您只想要它们的MAX 值,那么您将创建m1 和@987654337 @ 在我上面的查询子查询中:

...
    inner join
(select Class,MAX(Value) from @t where Member='m1' group by Class) m1
    on
        l.Class = m1.Class
...

【讨论】:

  • 感谢您的尝试,但我确实说过,除了坚持使用 PIVOT 之外,我不想要任何其他选择,例如 CASEes。我完全意识到可能有许多其他方法可以解决它。只是从这些方面,我想要 PIVOT 的一些东西。
  • @user1589188 - 好吧,我可以更新我的答案并让它说“不” - 但我认为这不会是一个非常有用的答案(即使它是正确的)
  • 谢谢。我真的很感激人们能用他所有的知识勇敢地回答“不”。我真的是。但我们都知道,通常很难用“不”作为答案。大多数情况下,很难做到而不是没有。
  • @user1589188 - 或者,换一种说法 - 我们不需要需要 MS将PIVOT添加到SQL Server - 我们可以在引入之前进行数据透视(正如你所说,通过使用带有CASE 表达式的聚合) - 所以它是一个简单案例的有效语法糖。如果简单的案例没有做你想做的事,那么你必须放弃糖并恢复“手动”做枢轴。
  • 是的,我完全理解你的意思。事实上,我的问题正是问我们是否可以使用这种好糖,并通过一些接触来解决稍微复杂的问题。我的标题,内容,从来都不是为了寻求解决问题的方法。所以我会接受“不”作为一个有效的答案,有证明或解释。
【解决方案2】:
SELECT  a.*, 
        b.Value
FROM    
        (
            SELECT  Class,
                    MAX(CASE WHEN Member = 'm1' THEN Value ELSE NULL END) [Member 1],
                    MAX(CASE WHEN Member = 'm2' THEN Value ELSE NULL END) [Member 2]
            FROM  tableName
            GROUP BY Class
        ) a 
        INNER JOIN
        (
            SELECT  Class, Value
            FROM    tableName 
            WHERE   Member = 'List'
        ) b ON a.Class = b.Class

结果

╔═══════╦══════════╦══════════╦═══════╗
║ CLASS ║ MEMBER 1 ║ MEMBER 2 ║ VALUE ║
╠═══════╬══════════╬══════════╬═══════╣
║ c1    ║       10 ║       20 ║    30 ║
║ c1    ║       10 ║       20 ║    40 ║
║ c1    ║       10 ║       20 ║    50 ║
║ c2    ║       60 ║       70 ║    80 ║
╚═══════╩══════════╩══════════╩═══════╝

【讨论】:

  • 这不是和正常枢轴一样的结果,OP 说他们不想要的结果吗?
  • @Damien_The_Unbeliever 是的,已修复。
  • 感谢您的尝试,但我确实说过,除了坚持使用 PIVOT 之外,我不想要任何其他选择,例如 CASEes。我完全意识到可能有许多其他方法可以解决它。只是从这些方面,我想要 PIVOT 的一些东西。
  • @JW。出于兴趣,您是如何生成 ascii 表图像的? :-)
猜你喜欢
  • 2017-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-14
  • 2019-09-01
  • 2021-06-29
  • 2011-05-19
  • 1970-01-01
相关资源
最近更新 更多