Dynamic Pivot table query with condition

I have the following table with the details as shown below in the example.

Example :

Table: test

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

Insertion :

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');    

Note : Now I want to show only that records in which cola belongs to colc 's values A1,A2,A3 .

Expected Result :

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

Attempt:

Pivot Query :

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)      

Getting Result :

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

The key to getting the result will be to first return the cola values that have A1 , A2 , and A3 in colc . Using IN is basically saying A1 or A2 or A3 so you will return rows that have one of these, not all of them.

In order you get the cola rows that have all of them, you will need to use a GROUP BY and a HAVING clause to go along with your WHERE clause filter. The basic query would be:

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

See SQL Fiddle with Demo. Breaking the query down, you'll see there is a WHERE clause to filter your colc values. You will use GROUP BY on cola along with a HAVING clause. The HAVING is used to the get the distinct number of colc values. In this case, the HAVING clause will be checking for rows that have a total of 3 colc values when filtered.

Once you have this list, then you can get the final result. Instead of using PIVOT you can use an aggregate function with a CASE expression.

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;

See SQL Fiddle with Demo

Typically you'd use dynamic SQL for data that you have unknown values on but if you want to use it for this, you can use the following query:

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;

See SQL Fiddle with Demo


你还必须过滤源数据:

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)   

Try this. To filter the Cola values that have A1 , A2 , and A3 in colc use 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 

OUTPUT :

+-----+----+---+----+  
|cola | A1 | A2| A3 |
+-----+----+---+----+
|111  | 1  | 1 | 1  |
|767  | 1  | 1 | 1  |
+-----+----+---+----+ 
链接地址: http://www.djcxy.com/p/23574.html

上一篇: 为什么typedef声明不称为typedef定义?

下一篇: 带条件的动态数据透视表查询