SQL 服务器:对多列进行透视
SQL Server : pivot on multiple columns
嗯,我花了 10 分钟才得到正确的标题,而且我不确定它是否涵盖了我的问题。一些背景信息:我的 table 包含来自多个服务器的备份结果。为简单起见,一些行仅用于一台服务器:
hostname type_id result_id received
----------------------------------------
SBS2011 5 1 2016-06-28
SBS2011 5 1 2016-06-28
SBS2011 5 1 2016-06-29
SBS2011 5 1 2016-06-29
SBS2011 5 1 2016-06-30
SBS2011 6 1 2016-06-30
SBS2011 5 2 2016-07-01
SBS2011 6 2 2016-07-01
SBS2011 6 2 2016-07-01
SBS2011 5 1 2016-07-02
SBS2011 6 1 2016-07-02
SBS2011 5 1 2016-07-03
SBS2011 6 1 2016-07-03
SBS2011 5 1 2016-07-04
SBS2011 6 1 2016-07-04
使用 PIVOT,我可以大致了解每个工作日的备份量:
select * from
(
select [hostname], [type_id], datepart(w, received) as workday from [backups]
) TEMP
pivot (
count([type_id])
for workday in
([1], [2], [3], [4], [5], [6], [7])
) as pvt;
结果:
hostname 1 2 3 4 5 6 7
--------------------------------------
SBS2011 2 2 2 2 2 3 2
但是这个结果遗漏了一些关键信息。由于 result_id 等于 'success' 而 result_id 等于 'failed',我希望结果如下所示:
hostname 1:1 1:2 2:1 2:2 3:1 3:2 4:1 4:2 5:1 5:2 6:1 6:2 7:1 7:2
-------------------------------------------------------------------
SBS2011 2 0 2 0 2 0 2 0 2 0 0 3 2 0
其中列名 1:1 对于 sunday:success 是 shorthand,并且 1:2 等于 sunday:failed。对于某些备份 type_id,可能还有一列 1:3 用于 sunday:retry。
环顾四周,我发现 DYNAMIC PIVOT 可能是解决这个难题的关键。其他人建议使用 PARTITION BY,但我还没有找到方法。 DYNAMIC PIVOT 似乎是最有前途的,但我不知道如何。请帮我创建这个 - 对我来说很复杂 - 查询?
检查一下,看看它是否能解决您的问题...我可以肯定我可以进一步简化它,但需要知道 type_id(5 和 6)的解码是什么。会有更多 type_id 吗?
还有 result_id = 1 = 成功和 2 = 失败对吗?
问题是,当备份在特定日期根本 运行 时会发生什么:)?你如何处理这种情况,因为那天没有记录。 :)
/* Create table and populate with sample data.
create table Backups (hostname varchar(10), type_id int , result_id int , received datetime)
insert into Backups (hostname , type_id ,result_id , received ) values
('SBS2011', 5 , 1 ,'2016-06-28'),
('SBS2011', 5 , 1 ,'2016-06-28'),
('SBS2011', 5 , 1 ,'2016-06-29'),
('SBS2011', 5 , 1 ,'2016-06-29'),
('SBS2011', 5 , 1 ,'2016-06-30'),
('SBS2011', 6 , 1 ,'2016-06-30'),
('SBS2011', 5 , 2 ,'2016-07-01'),
('SBS2011', 6 , 2 ,'2016-07-01'),
('SBS2011', 6 , 2 ,'2016-07-01'),
('SBS2011', 5 , 1 ,'2016-07-02'),
('SBS2011', 6 , 1 ,'2016-07-02'),
('SBS2011', 5 , 1 ,'2016-07-03'),
('SBS2011', 6 , 1 ,'2016-07-03'),
('SBS2011', 5 , 1 ,'2016-07-04'),
('SBS2011', 6 , 1 ,'2016-07-04')
select * , DatePart(w, received) from dbo.Backups b
*/
查询:
SELECT -- S.*, F.*
S.[hostname],
S.[1] as [1:1],
F.[1] as [1:2],
S.[2] as [2:1],
F.[2] as [2:2],
S.[3] as [3:1],
F.[3] as [3:2],
S.[4] as [4:1],
F.[4] as [4:2],
S.[5] as [5:1],
F.[5] as [5:2],
S.[6] as [6:1],
F.[6] as [6:2],
S.[7] as [7:1],
F.[7] as [7:2]
FROM
(
select * from
(
select [hostname], [type_id], datepart(w, received) as workday , result_id as res_type from [backups] where result_id = 1
) TEMP
pivot
(
count([type_id])
for workday in
([1], [2], [3], [4], [5], [6], [7])
) as pvt
) S
LEFT OUTER JOIN
(
select * from
(
select [hostname], [type_id], datepart(w, received) as workday , result_id as res_type from [backups] where result_id = 2
) TEMP
pivot
(
count([type_id])
for workday in
([1], [2], [3], [4], [5], [6], [7])
) as pvt
) F ON S.res_type = F.res_type - 1
WHERE F.hostname IS NOT NULL
如果您不想 fiddle 使用动态 SQL,您可以保持静态并更改旋转的列。
查询如:
select *
from
(
select
[hostname],
[type_id],
concat(datepart(w, received),':',result_id) as workday
from [backups]
) TEMP
pivot (
count([type_id])
for workday in (
-- maybe you don't want the :3 option for all days? Adjust as needed
[1:1],[1:2],[1:3],
[2:1],[2:2],[2:3],
[3:1],[3:2],[3:3],
[4:1],[4:2],[4:3],
[5:1],[5:2],[5:3],
[6:1],[6:2],[6:3],
[7:1],[7:2],[7:3]
)
) as pvt;
可能会给出类似于您想要的结果?
嗯,我花了 10 分钟才得到正确的标题,而且我不确定它是否涵盖了我的问题。一些背景信息:我的 table 包含来自多个服务器的备份结果。为简单起见,一些行仅用于一台服务器:
hostname type_id result_id received
----------------------------------------
SBS2011 5 1 2016-06-28
SBS2011 5 1 2016-06-28
SBS2011 5 1 2016-06-29
SBS2011 5 1 2016-06-29
SBS2011 5 1 2016-06-30
SBS2011 6 1 2016-06-30
SBS2011 5 2 2016-07-01
SBS2011 6 2 2016-07-01
SBS2011 6 2 2016-07-01
SBS2011 5 1 2016-07-02
SBS2011 6 1 2016-07-02
SBS2011 5 1 2016-07-03
SBS2011 6 1 2016-07-03
SBS2011 5 1 2016-07-04
SBS2011 6 1 2016-07-04
使用 PIVOT,我可以大致了解每个工作日的备份量:
select * from
(
select [hostname], [type_id], datepart(w, received) as workday from [backups]
) TEMP
pivot (
count([type_id])
for workday in
([1], [2], [3], [4], [5], [6], [7])
) as pvt;
结果:
hostname 1 2 3 4 5 6 7
--------------------------------------
SBS2011 2 2 2 2 2 3 2
但是这个结果遗漏了一些关键信息。由于 result_id 等于 'success' 而 result_id 等于 'failed',我希望结果如下所示:
hostname 1:1 1:2 2:1 2:2 3:1 3:2 4:1 4:2 5:1 5:2 6:1 6:2 7:1 7:2
-------------------------------------------------------------------
SBS2011 2 0 2 0 2 0 2 0 2 0 0 3 2 0
其中列名 1:1 对于 sunday:success 是 shorthand,并且 1:2 等于 sunday:failed。对于某些备份 type_id,可能还有一列 1:3 用于 sunday:retry。
环顾四周,我发现 DYNAMIC PIVOT 可能是解决这个难题的关键。其他人建议使用 PARTITION BY,但我还没有找到方法。 DYNAMIC PIVOT 似乎是最有前途的,但我不知道如何。请帮我创建这个 - 对我来说很复杂 - 查询?
检查一下,看看它是否能解决您的问题...我可以肯定我可以进一步简化它,但需要知道 type_id(5 和 6)的解码是什么。会有更多 type_id 吗?
还有 result_id = 1 = 成功和 2 = 失败对吗?
问题是,当备份在特定日期根本 运行 时会发生什么:)?你如何处理这种情况,因为那天没有记录。 :)
/* Create table and populate with sample data.
create table Backups (hostname varchar(10), type_id int , result_id int , received datetime)
insert into Backups (hostname , type_id ,result_id , received ) values
('SBS2011', 5 , 1 ,'2016-06-28'),
('SBS2011', 5 , 1 ,'2016-06-28'),
('SBS2011', 5 , 1 ,'2016-06-29'),
('SBS2011', 5 , 1 ,'2016-06-29'),
('SBS2011', 5 , 1 ,'2016-06-30'),
('SBS2011', 6 , 1 ,'2016-06-30'),
('SBS2011', 5 , 2 ,'2016-07-01'),
('SBS2011', 6 , 2 ,'2016-07-01'),
('SBS2011', 6 , 2 ,'2016-07-01'),
('SBS2011', 5 , 1 ,'2016-07-02'),
('SBS2011', 6 , 1 ,'2016-07-02'),
('SBS2011', 5 , 1 ,'2016-07-03'),
('SBS2011', 6 , 1 ,'2016-07-03'),
('SBS2011', 5 , 1 ,'2016-07-04'),
('SBS2011', 6 , 1 ,'2016-07-04')
select * , DatePart(w, received) from dbo.Backups b
*/
查询:
SELECT -- S.*, F.*
S.[hostname],
S.[1] as [1:1],
F.[1] as [1:2],
S.[2] as [2:1],
F.[2] as [2:2],
S.[3] as [3:1],
F.[3] as [3:2],
S.[4] as [4:1],
F.[4] as [4:2],
S.[5] as [5:1],
F.[5] as [5:2],
S.[6] as [6:1],
F.[6] as [6:2],
S.[7] as [7:1],
F.[7] as [7:2]
FROM
(
select * from
(
select [hostname], [type_id], datepart(w, received) as workday , result_id as res_type from [backups] where result_id = 1
) TEMP
pivot
(
count([type_id])
for workday in
([1], [2], [3], [4], [5], [6], [7])
) as pvt
) S
LEFT OUTER JOIN
(
select * from
(
select [hostname], [type_id], datepart(w, received) as workday , result_id as res_type from [backups] where result_id = 2
) TEMP
pivot
(
count([type_id])
for workday in
([1], [2], [3], [4], [5], [6], [7])
) as pvt
) F ON S.res_type = F.res_type - 1
WHERE F.hostname IS NOT NULL
如果您不想 fiddle 使用动态 SQL,您可以保持静态并更改旋转的列。
查询如:
select *
from
(
select
[hostname],
[type_id],
concat(datepart(w, received),':',result_id) as workday
from [backups]
) TEMP
pivot (
count([type_id])
for workday in (
-- maybe you don't want the :3 option for all days? Adjust as needed
[1:1],[1:2],[1:3],
[2:1],[2:2],[2:3],
[3:1],[3:2],[3:3],
[4:1],[4:2],[4:3],
[5:1],[5:2],[5:3],
[6:1],[6:2],[6:3],
[7:1],[7:2],[7:3]
)
) as pvt;
可能会给出类似于您想要的结果?