SQL Server:在多个列上进行透视

时间:2016-07-04 20:32:50

标签: sql sql-server pivot

嗯,只有得到正确的标题花了我10分钟,我不确定我是否覆盖了我的问题。一些背景信息:我的表包含来自多个服务器的备份结果。为简单起见,只有一个服务器的行:

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

其中columnname 1:1是sunday的简写:success和1:2等于sunday:failed。对于某些备份type_id,星期日可能还有一列1:3:重试。

当我环顾四周时,我发现一个动态的PIVOT可能是解决这个难题的关键。其他人提出了PARTITION BY,但我还没有发现如何。 DYNAMIC PIVOT似乎是最有希望的,但我不知道如何。请帮我创建这个 - 对我来说复杂 - 查询?

2 个答案:

答案 0 :(得分:0)

检查一下,看看它是否解决了你的问题...我非常确定我可以进一步简化这一点,但需要知道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

答案 1 :(得分:0)

如果您不想使用动态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;

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