我想计算每年不同的 PID 和 VID 计数。
条件:
1. Separate count for column A or B or C or D having value 1 ( A_to_D)
2. Separate count for column E having value 1 (E)
3. Separate count for column F having value 1 (F)
4. Separate count for ALL A to F column are NULL (ALL_NULL)
在输出中,我想要一个单独的新列 Alpha ,其中包含以下值:
A_to_D, E, F and ALL_Null
表的当前输出:
PID VID Flag Date A B C D E F
1 A1 0 10/17/2013 NULL NULL NULL NULL NULL NULL
2 A2 1 5/27/2014 1 NULL NULL 1 NULL NULL
3 A3 NULL 2/23/2015 NULL NULL NULL NULL 1 NULL
4 A4 NULL 12/6/2013 NULL 0 NULL NULL NULL NULL
5 A5 NULL 7/14/2016 NULL NULL NULL NULL NULL 1
6 A6 NULL 4/29/2015 NULL 1 1 NULL NULL NULL
7 A7 1 9/30/2016 1 NULL NULL NULL NULL NULL
8 A8 NULL 6/28/2016 NULL NULL NULL NULL NULL NULL
9 A9 1 11/20/2013 NULL NULL NULL NULL NULL NULL
10 A10 2 10/8/2015 NULL 1 NULL NULL NULL NULL
这里:
select datepart(Year,date) ,Count(distinct PID) ,Count( distinct VID)
from table
where A is not null or B is Not NUll or C is not null
or D is not null or E is not Null or F is not null
group by datepart(Year,date)
预期输出:
Year Count_PID Count_VID Alpha
2013 A_to_D
2013 E
2013 F
2013 2 2 ALL_NULL
2014 1 1 A_to_D
2014 E
2014 F
2014 ALL_NULL
2015 2 2 A_to_D
2015 1 1 E
2015 F
2015 ALL_NULL
2016 2 2 A_to_D
2016 E
2016 1 F
2016 1 ALL_NULL
最佳答案
我选择使用公用表表达式
(cte) 来保存基本计数,这些基本计数是使用 case 表达式针对 8 个不同条件(4 个用于 PID,4 个用于 VID)中的每一个条件形成的。然后,cte
用作最终结果所需的年份维度的来源,该最终结果交叉连接到 4 个 alpha 标签的列表。然后再次使用 cte(两次)(未旋转)以将计数左连接到所请求的最终行结构中。该结果中的 Null 是故意的,但如果需要,可以通过在最终 select 子句中使用 coalesce()
或 isnull()
来替换为空字符串。请注意,我更喜欢使用 cross apply
和 values
进行“unpivot”,因为它允许对生成的行进行几乎所见即所得的布局,因为它至少与 具有相同的效率>unpivot
命令(引用如下)。
演示地址: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)
;
建议的查询:
/* 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 |
有关使用 CROSS APPLY 和 VALUES 进行 UNPIVOT 的详细信息,请参阅 Spotlight on UNPIVOT, Part 1作者:布拉德·舒尔茨
最内部查询:
查看初始结果有助于跟踪后续操作。这是 cte 中最里面的子查询,作为单独的查询,结果如下:
/* 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) |
关于sql - 如何根据 SQL Server 中的值取消透视列和 GROUP BY?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47199461/