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;

可能会给出类似于您想要的结果?