【问题标题】:Dynamic Pivot table query with condition带条件的动态数据透视表查询
【发布时间】:2014-11-20 10:06:35
【问题描述】:

我有下表,详细信息如下示例所示。

示例

表格:测试

create table test
(
 cola varchar(10),
 colb varchar(10),
 colc varchar(10)
);

插入

insert into test values('111','222','A1');
insert into test values('111','333','A2');
insert into test values('111','344','A3');
insert into test values('111','444','A4');
insert into test values('767','222','A1');
insert into test values('767','333','A2');
insert into test values('767','344','A3');
insert into test values('5443','555','B1');
insert into tft values('8998','222','A1');
insert into tft values('8998','333','A2');    

注意:现在我只想显示cola 属于colc 的值A1,A2,A3 的记录。

预期结果

cola   A1  A2  A3
------------------
111    1   1   1
767    1   1   1

尝试:

透视查询

DECLARE @Stuff varchar(max) = 'A1,A2,A3'
DECLARE @Sql varchar(max)

SET @Sql = 'SELECT cola,' +@Stuff+ '
            from
            (
                select cola,colc
                from test 
            )p
            PIVOT
            (
                COUNT(colc)
                FOR colc IN ('+@Stuff+')
            )AS pvt'

PRINT(@Sql)
EXEC(@Sql)      

获取结果

cola    A1  A2  A3
-------------------
111     1   1   1
5443    0   0   0
767     1   1   1
8998    1   1   0

【问题讨论】:

    标签: sql-server sql-server-2008-r2 pivot


    【解决方案1】:

    获得结果的关键是首先在colc 中返回具有A1A2A3cola 值。使用IN 基本上是说A1A2A3,因此您将返回具有其中之一的行,而不是所有行。

    为了获得包含所有这些行的cola 行,您需要使用GROUP BYHAVING 子句与WHERE 子句过滤器一起使用。基本查询是:

    select cola
    from test
    where colc in ('A1', 'A2', 'A3')
    group by cola
    having count(distinct colc) = 3;
    

    SQL Fiddle with Demo。分解查询,您会看到有一个 WHERE 子句来过滤您的 colc 值。您将在 cola 上使用 GROUP BY 以及 HAVING 子句。 HAVING 用于获取不同数量的 colc 值。在这种情况下,HAVING 子句将在过滤时检查总共有 3 个 colc 值的行。

    一旦你有了这个列表,你就可以得到最终的结果。您可以使用带有CASE 表达式的聚合函数,而不是使用PIVOT

    select 
      t.cola, 
      sum(case when t.colc = 'A1' then 1 else 0 end) A1,
      sum(case when t.colc = 'A2' then 1 else 0 end) A2,
      sum(case when t.colc = 'A3' then 1 else 0 end) A3
    from test t
    inner join
    (
      select cola
      from test
      where colc in ('A1', 'A2', 'A3')
      group by cola
      having count(distinct colc) = 3
    ) d
      on t.cola = d.cola
    group by t.cola;
    

    SQL Fiddle with Demo

    通常,您会对具有未知值的数据使用动态 SQL,但如果您想为此使用它,可以使用以下查询:

    DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)
    
    select @cols = 'A1, A2, A3'
    
    set @query = N'SELECT cola, ' + @cols + N' 
                from 
                (
                  select t.cola, t.colc
                  from test t
                  inner join
                  (
                    select cola
                    from test
                    where colc in (''A1'', ''A2'', ''A3'')
                    group by cola
                    having count(distinct colc) = 3
                  ) d
                    on t.cola = d.cola
                ) x
                pivot 
                (
                    count(colc)
                    for colc in (' + @cols + N')
                ) p '
    
    exec sp_executesql @query;
    

    SQL Fiddle with Demo

    【讨论】:

    • 这就是我要找的!非常感谢。
    • 上述动态查询还是有错误的结果。因为如果你通过@Stuff = A1,A2,A3 那么它必须只显示记录767 而不是111。因为记录 767 恰好属于 A1,A2,A3111 属于 A1,A2,A3A4 也因此它应该出现在结果中。
    • @MAK 问题已被回答后,您将无法更改。如果您有新的要求,那么您应该发布一个带有那些要求的新问题。我已经回滚了您更改问题的编辑。
    • 好吧好吧。我现在就去做。
    【解决方案2】:

    您还必须过滤源数据:

    DECLARE @Stuff varchar(max) = 'A1,A2,A3'
    DECLARE @StuffForFilter varchar(max) = '''A1'',''A2'',''A3'''
    DECLARE @Sql varchar(max)
    
    SET @Sql = 'SELECT cola,' +@Stuff+ '
                from
                (
                    select cola,colc
                    from test
                    where colc IN ('+@StuffForFilter+')
                )p
                PIVOT
                (
                    COUNT(colc)
                    FOR colc IN ('+@Stuff+')
                )AS pvt'
    
    PRINT(@Sql)
    EXEC(@Sql)   
    

    【讨论】:

    • 收到错误Msg 207, Level 16, State 1, Line 6 Invalid column name 'A3'. Msg 207, Level 16, State 1, Line 6 Invalid column name 'A2'. Msg 207, Level 16, State 1, Line 6 Invalid column name 'A1'
    • @MAK 请看我的编辑;糟糕的是,我在发布之前没有测试我的代码
    • 快完成了,但仍然需要满足我更新后的最后一条记录,即8998
    【解决方案3】:

    试试这个。要过滤在colc 中具有A1A2A3Cola 值,请使用conditional aggregate

    DECLARE @Stuff varchar(max) = 'A1,A2,A3'
    DECLARE @StuffForFilter varchar(max) = '''A1'',''A2'',''A3'''
    DECLARE @Sql Nvarchar(max)
    
    SET @Sql = 'SELECT cola,' +@Stuff+ '
                from
                (
                    select  t.cola,t.colc
                    from #test t join (SELECT cola from (SELECT Max(CASE WHEN colc = ''A1'' THEN 1 END) [a1],
                   Max(CASE WHEN colc = ''A2'' THEN 2 END) [a2],
                   Max(CASE WHEN colc = ''A3'' THEN 3 END) [a3] ,
                   cola
            FROM   #test
            WHERE  colc IN( '+@StuffForFilter+' )
            GROUP  BY cola) A
    WHERE  [a1] IS NOT NULL
           AND [a2] IS NOT NULL
           AND [a3] IS NOT NULL ) B on t.cola=B.cola 
                )p
                PIVOT
                (
                    COUNT(colc)
                    FOR colc IN ('+@Stuff+')
                )AS pvt'
    
    EXEC sp_executesql @Sql 
    

    输出:

    +-----+----+---+----+  
    |cola | A1 | A2| A3 |
    +-----+----+---+----+
    |111  | 1  | 1 | 1  |
    |767  | 1  | 1 | 1  |
    +-----+----+---+----+ 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      • 2016-06-30
      • 1970-01-01
      • 2021-06-13
      相关资源
      最近更新 更多