Sql server 具有多个聚合列和总计列的SQL Server PIVOT

Sql server 具有多个聚合列和总计列的SQL Server PIVOT,sql-server,tsql,pivot,pivot-table,aggregate,Sql Server,Tsql,Pivot,Pivot Table,Aggregate,我想生成一个数据透视表,每个数据透视列有2个总和聚合。然后在轴列的右侧,我想要一些总列。最后,轴列的数量是动态的。我的首选结果如下所示: 我的数据如下所示: 从答案来看,我已经非常接近解决它了。以下是我所拥有的: SELECT * FROM ( SELECT B.SiteID, R.BuildingID, C.* FROM Rooms R JOIN Buildings B ON R.BuildingID = B.BuildingID CROSS APP

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

我的数据如下所示:

从答案来看,我已经非常接近解决它了。以下是我所拥有的:

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之外执行两行标题。我需要的帮助是如何添加总列。另外,除了我在很多地方看到的解决方案之外,还有更好的动态列解决方案吗

以下是创建示例数据的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)

下面是使用
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
创建列表之外,您知道另一种创建动态列的方法(在我的例子中,roomtype的数量未知)吗?