I chose to use a common table expression
(cte) to hold the basic counts which are formed using case expressions for each of 8 different conditions (4 for PIDs and 4 for VIDs). The cte
is then used as a source of the year dimension needed for the final result which gets cross joined to the list of 4 alpha labels. Then the cte is used again (twice) - unpivoted - to enable left joining the counts into the requested final row structure. Nulls in that results are deliberate, but could be replaced with empty string if required by using coalesce()
or isnull()
in the final select clause. Note I prefer to "unpivot" using cross apply
and values
as it allows an almost WYSIWYG layout of the rows that get produced as it at least a equally efficient as the unpivot
command (ref below).
Demo at: SQL Fiddle
CREATE TABLE Table1
([PID] int, [VID] varchar(3), [Flag] varchar(4), [Date] datetime, [A] varchar(4), [B] varchar(4), [C] varchar(4), [D] varchar(4), [E] varchar(4), [F] varchar(4))
;
INSERT INTO Table1
([PID], [VID], [Flag], [Date], [A], [B], [C], [D], [E], [F])
VALUES
(1, 'A1', '0', '2013-10-17 00:00:00', NULL, NULL, NULL, NULL, NULL, NULL),
(2, 'A2', '1', '2014-05-27 00:00:00', '1', NULL, NULL, '1', NULL, NULL),
(3, 'A3', NULL, '2015-02-23 00:00:00', NULL, NULL, NULL, NULL, '1', NULL),
(4, 'A4', NULL, '2013-12-06 00:00:00', NULL, '0', NULL, NULL, NULL, NULL),
(5, 'A5', NULL, '2016-07-14 00:00:00', NULL, NULL, NULL, NULL, NULL, '1'),
(6, 'A6', NULL, '2015-04-29 00:00:00', NULL, '1', '1', NULL, NULL, NULL),
(7, 'A7', '1', '2016-09-30 00:00:00', '1', NULL, NULL, NULL, NULL, NULL),
(8, 'A8', NULL, '2016-06-28 00:00:00', NULL, NULL, NULL, NULL, NULL, NULL),
(9, 'A9', '1', '2013-11-20 00:00:00', NULL, NULL, NULL, NULL, NULL, NULL),
(10, 'A10', '2', '2015-10-08 00:00:00', NULL, '1', NULL, NULL, NULL, NULL)
;
Proposed Query:
/* common table expression used so the results may be reused */
with cte as (
select
year([date]) [Year]
, count(distinct pA_to_D) pA_to_D
, count(distinct pE) pE
, count(distinct pF) pF
, count(distinct pALL_NULL) pALL_NULL
, count(distinct vA_to_D) vA_to_D
, count(distinct vE) vE
, count(distinct vF) vF
, count(distinct vALL_NULL) vALL_NULL
from (
select
pid, vid, flag, [date]
, case when a = 1 or b = 1 or c = 1 or d = 1 then pid end pA_to_D
, case when E = 1 then pid end pE
, case when F = 1 then pid end pF
, case when coalesce(a,b,c,d,e,f) IS NULL then pid end pALL_NULL
, case when flag is not null and a = 1 or b = 1 or c = 1 or d = 1 then vid end vA_to_D
, case when flag is not null and E = 1 then vid end vE
, case when flag is not null and F = 1 then vid end vF
, case when flag is not null and coalesce(a,b,c,d,e,f) IS NULL then vid end vALL_NULL
from Table1
) t
group by
year([date])
)
select
y.[Year], p.count_pid, v.count_vid, a.alpha
from (select distinct [Year] from cte) y
cross join (
select 'A_to_D' as Alpha union all
select 'E' union all
select 'F' union all
select 'ALL_NULL'
) a
left join (
select cte.Year, ca.alpha, ca.count_pid
from cte
cross apply (
values
('A_to_D' ,pA_to_D)
, ('E' ,pE)
, ('F' ,pF)
, ('ALL_NULL',pALL_NULL)
) ca (alpha, count_pid)
where ca.count_pid > 0
) p on y.[Year] = p.[Year] and a.alpha = p.alpha
left join (
select cte.Year, ca.alpha, ca.count_vid
from cte
cross apply (
values
('A_to_D' ,vA_to_D)
, ('E' ,vE)
, ('F' ,vF)
, ('ALL_NULL',vALL_NULL)
) ca (alpha, count_vid)
where ca.count_vid > 0
) v on y.[Year] = v.[Year] and a.alpha = v.alpha
;
Results:
| Year | count_pid | count_vid | alpha |
|------|-----------|-----------|----------|
| 2013 | (null) | (null) | A_to_D |
| 2013 | (null) | (null) | E |
| 2013 | (null) | (null) | F |
| 2013 | 2 | 2 | ALL_NULL |
| 2014 | 1 | 1 | A_to_D |
| 2014 | (null) | (null) | E |
| 2014 | (null) | (null) | F |
| 2014 | (null) | (null) | ALL_NULL |
| 2015 | 2 | 2 | A_to_D |
| 2015 | 1 | (null) | E |
| 2015 | (null) | (null) | F |
| 2015 | (null) | (null) | ALL_NULL |
| 2016 | 1 | 1 | A_to_D |
| 2016 | (null) | (null) | E |
| 2016 | 1 | (null) | F |
| 2016 | 1 | (null) | ALL_NULL |
For details on using CROSS APPLY and VALUES to UNPIVOT, see Spotlight on UNPIVOT, Part 1 by Brad Schultz
Innermost Query:
It can be useful to see the initial results to help trace following actions. This is he innermost subquery within the cte as a separate query with the results below:
/* initial results, prior to unpivot */
select
pid, vid, flag, [date]
, case when a = 1 or b = 1 or c = 1 or d = 1 then pid end pA_to_D
, case when E = 1 then pid end pE
, case when F = 1 then pid end pF
, case when coalesce(a,b,c,d,e,f) IS NULL then pid end pALL_NULL
, case when flag is not null and a = 1 or b = 1 or c = 1 or d = 1 then vid end vA_to_D
, case when flag is not null and E = 1 then vid end vE
, case when flag is not null and F = 1 then vid end vF
, case when flag is not null and coalesce(a,b,c,d,e,f) IS NULL then vid end vALL_NULL
from Table1
order by [date]
;
Results:
| pid | vid | flag | date | pA_to_D | pE | pF | pALL_NULL | vA_to_D | vE | vF | vALL_NULL |
|-----|-----|--------|----------------------|---------|--------|--------|-----------|---------|--------|--------|-----------|
| 1 | A1 | 0 | 2013-10-17T00:00:00Z | (null) | (null) | (null) | 1 | (null) | (null) | (null) | A1 |
| 9 | A9 | 1 | 2013-11-20T00:00:00Z | (null) | (null) | (null) | 9 | (null) | (null) | (null) | A9 |
| 4 | A4 | (null) | 2013-12-06T00:00:00Z | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
| 2 | A2 | 1 | 2014-05-27T00:00:00Z | 2 | (null) | (null) | (null) | A2 | (null) | (null) | (null) |
| 3 | A3 | (null) | 2015-02-23T00:00:00Z | (null) | 3 | (null) | (null) | (null) | (null) | (null) | (null) |
| 6 | A6 | (null) | 2015-04-29T00:00:00Z | 6 | (null) | (null) | (null) | A6 | (null) | (null) | (null) |
| 10 | A10 | 2 | 2015-10-08T00:00:00Z | 10 | (null) | (null) | (null) | A10 | (null) | (null) | (null) |
| 8 | A8 | (null) | 2016-06-28T00:00:00Z | (null) | (null) | (null) | 8 | (null) | (null) | (null) | (null) |
| 5 | A5 | (null) | 2016-07-14T00:00:00Z | (null) | (null) | 5 | (null) | (null) | (null) | (null) | (null) |
| 7 | A7 | 1 | 2016-09-30T00:00:00Z | 7 | (null) | (null) | (null) | A7 | (null) | (null) | (null) |