【问题标题】:SQL Server PIVOT with Multiple Aggregate Columns and Totals Columns具有多个聚合列和总计列的 SQL Server PIVOT
【发布时间】:2018-06-28 20:36:15
【问题描述】:

我想生成一个数据透视表,每个数据透视列有 2 个总和聚合。然后在数据透视列的右侧,我想要一些总列。最后,数据透视列的数量是动态的。我的首选结果如下所示:

我的数据如下所示:

来自this 的回答,我已经非常接近解决它了。这是我所拥有的:

SELECT *
FROM (
    SELECT B.SiteID, R.BuildingID, C.*
    FROM Rooms R JOIN Buildings B
        ON R.BuildingID = B.BuildingID
    CROSS APPLY (
        VALUES(RTRIM(RoomType) + ' NASF', AreaNASF)
             ,(RTRIM(RoomType) + ' RSF', AreaRSF)
        ) C (Item,Value)
) src
PIVOT (
    SUM([Value])
    FOR [Item] IN ([CONFERENCE NASF], [CONFERENCE RSF], [OFFICE NASF], [OFFICE RSF], [STORAGE NASF], [STORAGE RSF])
) pvt

产生:

我的印象是我必须在 SQL 之外执行两行标题。我需要帮助的是如何添加总列。另外,除了我在很多地方见过的STUFF 解决方案之外,还有没有更好的动态列解决方案?

这里是创建示例数据的 SQL:

CREATE TABLE Buildings (
    BuildingID CHAR(12),
    SiteID CHAR(12),
    Name VARCHAR(100),
    CONSTRAINT PK_Building PRIMARY KEY (BuildingID)
);

CREATE TABLE Rooms (
    BuildingID CHAR(12),
    FloorID CHAR(4),
    RoomID CHAR(8),
    RoomType CHAR(16),
    Dept CHAR(16),
    AreaNASF NUMERIC(12,2),
    AreaRSF NUMERIC(12,2),
    CONSTRAINT FK_Rooms_BuildingID FOREIGN KEY (BuildingID) REFERENCES Buildings(BuildingID),
    CONSTRAINT PK_Rooms PRIMARY KEY (BuildingID, FloorID, RoomID)
);

INSERT INTO Buildings (BuildingID, SiteID, Name) VALUES 
    ('100', 'Main', 'Headquarters'),
    ('200', 'Main', 'Technology'),
    ('300', 'Fleet', 'Fleet')

INSERT INTO Rooms (BuildingID, FloorID, RoomID, RoomType, Dept, AreaNASF, AreaRSF) VALUES
     ('100', '01', '101', 'CONFERENCE', 'FINANCE', 206.84, 207.00)
    ,('100', '01', '102', 'OFFICE', 'FINANCE', 100.55, 101.00)
    ,('100', '01', '103', 'OFFICE', 'FINANCE', 100.87, 101.00)
    ,('100', '02', '201', 'STORAGE', 'FINANCE', 56.15, 0.00)
    ,('100', '02', '202', 'CONFERENCE', 'FINANCE', 164.93, 160.00)
    ,('200', '01', '101', 'OFFICE', 'IT', 95.50, 96.00)
    ,('200', '01', '102', 'OFFICE', 'IT', 100.64, 100.00)
    ,('200', '01', '103', 'CONFERENCE', 'IT', 220.19, 220.00)
    ,('200', '01', '104', 'STORAGE', 'IT', 50.25, 0.00)
    ,('200', '02', '201', 'OFFICE', 'HR', 65.82, 66.00)
    ,('300', '01', '101', 'OFFICE', 'MAINTENANCE', 65.82, 66.00)
    ,('300', '01', '102', 'OFFICE', 'MAINTENANCE', 65.82, 66.00)

【问题讨论】:

    标签: sql-server tsql pivot pivot-table aggregate


    【解决方案1】:

    这是使用sum()Over() 窗口聚合函数的一种方法。这里的技巧是在旋转之前为每个BuildingID 预先聚合AreaNASF/AreaRSF

    SELECT *
    FROM   (SELECT B.SiteID,
                   R.BuildingID,
                   TotalAreaNASF,
                   TotalAreaRSF,
                   C.*
            FROM   (SELECT TotalAreaNASF = Sum(AreaNASF)OVER(partition BY BuildingID),
                           TotalAreaRSF= Sum(AreaRSF)OVER(partition BY BuildingID),*
                    FROM   Rooms) R
                   JOIN Buildings B
                     ON R.BuildingID = B.BuildingID
                   CROSS APPLY ( VALUES(Rtrim(RoomType) + ' NASF',AreaNASF),
                                       (Rtrim(RoomType) + ' RSF',AreaRSF) ) C (Item, Value)) src
           PIVOT ( Sum([Value])
                 FOR [Item] IN ([CONFERENCE NASF],
                                [CONFERENCE RSF],
                                [OFFICE NASF],
                                [OFFICE RSF],
                                [STORAGE NASF],
                                [STORAGE RSF]) ) pvt 
    

    如果RoomTypes的数量未知,那么这里是动态版本

    declare @col_list varchar(max),
        @sql varchar(max)
    
    set @col_list = stuff((select distinct ','+QUOTENAME(Rtrim(RoomType) + ' NASF')+','+QUOTENAME(Rtrim(RoomType) + ' RSF') from #Rooms for xml path('')),1,1,'')
    
    
    set @sql = '
    SELECT SiteID, BuildingID, '+@col_list+', [Total NASF], [Total RSF]
    FROM   (SELECT B.SiteID,
                   R.BuildingID,
                   [Total NASF],
                   [Total RSF],
                   C.*
            FROM   (SELECT [Total NASF] = Sum(AreaNASF)OVER(partition BY BuildingID),
                           [Total RSF] = Sum(AreaRSF)OVER(partition BY BuildingID),*
                    FROM   Rooms) R
                   JOIN Buildings B
                     ON R.BuildingID = B.BuildingID
                   CROSS APPLY ( VALUES(Rtrim(RoomType) + '' NASF'',AreaNASF),
                                       (Rtrim(RoomType) + '' RSF'',AreaRSF) ) C (Item, Value)) src
           PIVOT ( Sum([Value])
                 FOR [Item] IN ('+@col_list+') ) pvt ' 
    
    print @sql
    exec (@sql)
    

    【讨论】:

    • 谢谢,效果很好。有没有办法将总列向右移动?重新排序 select 语句似乎不起作用。另外,除了声明一个变量并使用STUFF 来制作列表之外,您是否知道另一种拥有动态列的方法(在我的情况下,RoomTypes 的数量是未知的)?
    猜你喜欢
    • 2010-11-17
    • 1970-01-01
    • 2012-10-15
    • 2014-11-27
    • 2019-02-27
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    • 2011-03-15
    相关资源
    最近更新 更多