Calc SUM total of pivoted table by two columns into predefined table?

时间:2018-09-22 22:48:52

标签: sql sql-server tsql sum pivot

Big thanks to @JohnCappelletti as he's shown how to pivot a table:

DECLARE @OperatorPrice TABLE (ID INT NOT NULL, OperatorId INT NULL, Price 
    NUMERIC(18,3) NULL, FName VARCHAR(50) NULL)

INSERT INTO @OperatorPrice (
    ID, OperatorId, Price, FName
)
VALUES
   (226, 996, 22954,'Operator1')
, (266, 1016, 79011.2,   'Operator3')
, (112, 1029, 14869,     'Operator4')
, (112, 996, 22954,      'Operator1')
, (93,   1031, 10568.96, 'Operator5')


DECLARE @TR TABLE 
(
ID INT NULL , 
Operator1  DECIMAL(18,3) NULL, OC1  DECIMAL(18,3) NULL, Operator2  DECIMAL(18,3) NULL, 
OC2  DECIMAL(18,3) NULL, Operator3  DECIMAL(18,3) NULL, OC3  DECIMAL(18,3) NULL, 
Operator4  DECIMAL(18,3) NULL, OC4  DECIMAL(18,3) NULL, Operator5  DECIMAL(18,3) NULL, 
OC5  DECIMAL(18,3) NULL
)

INSERT @TR
SELECT *
FROM  (
    Select A.ID
          ,B.*
     From  @OperatorPrice A
     Cross Apply ( values (FName,Price)
                         ,('OC'+replace(FName,'Operator',''),OperatorID)
                 ) B (Item,Value)
    Union All
    Select ID=(select min(ID) From @OperatorPrice)
          ,B.*
     From ( Select Top 50 N=Row_Number() Over (Order By (Select NULL)) 
            From master..spt_values n1 ) A
     Cross Apply ( values (concat('Operator',N),NULL)
                         ,(concat('OC',N),NULL)
                 ) B (Item,Value)
   ) AS SourceTable        
PIVOT  ( sum(Value) FOR Item IN (Operator1, OC1, Operator2, OC2,  
Operator3, OC3, Operator4, OC4,  Operator5, OC5) ) AS PivotTable

The above code works perfectly!

However, I would like the total sum for each column. So the desired ouput should looks like this:

ID     Operator1    OC1   Operator2   OC2   Operator3    OC3     Operator4  OC4   Operator5   OC5
Total  45908.000    1992    NULL      NULL    NULL      NULL     NULL      NULL    NULL   NULL
93     NULL         NULL    NULL      NULL    NULL      NULL     NULL      NULL   10568.96  1031
112    22954.000    996.0   NULL      NULL    NULL      NULL     14869.0  1029.000 NULL   NULL   
226    22954.000    996.0   NULL      NULL    NULL      NULL     14869.0  1029.000 NULL   NULL   
266    NULL         NULL    NULL      NULL   79011.200  1016.000    NULL    NULL   NULL    NULL  

or an image:enter image description here

I've tried to use the following code:

INSERT @TR
SELECT 
   Total = SUM([Operator1] + [OC1] + [Operator2] + [OC2] + [Operator3] + 
               [OC3]+ [Operator4] + [OC4] + [Operator5] + [OC5])
, *
FROM  (
    Select A.ID
          ,B.*
     From  @OperatorPrice A
     Cross Apply ( values (FName,Price)
                         ,('OC'+replace(FName,'Operator',''),OperatorID)
                 ) B (Item,Value)
    Union All
    Select ID=(select min(ID) From @OperatorPrice)
          ,B.*
     From ( Select Top 50 N=Row_Number() Over (Order By (Select NULL)) From 
     master..spt_values n1 ) A
     Cross Apply ( values (concat('Operator',N),NULL)
                         ,(concat('OC',N),NULL)
                 ) B (Item,Value)
   ) AS SourceTable        
   PIVOT  ( sum(Value) FOR Item IN (Operator1, OC1, Operator2, OC2,  
            Operator3, OC3, Operator4, OC4,  Operator5, OC5) ) AS PivotTable

But it doesn't work as it shows an error:

Msg 8120, Level 16, State 1, Line 24 Column 'PivotTable.ID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

How can I get SUM of each column and put this row at the first place?

2 个答案:

答案 0 :(得分:2)

Notice

  • The ID in @TR is now a varchar(25)
  • Added two "TOTAL" rows in the CROSS APPLY
  • After the Union All, I changed the ID to "Total"

.

DECLARE @OperatorPrice TABLE (ID int NOT NULL, OperatorId INT NULL, Price 
    NUMERIC(18,3) NULL, FName VARCHAR(50) NULL)

INSERT INTO @OperatorPrice (
    ID, OperatorId, Price, FName
)
VALUES
   (226, 996, 22954,'Operator1')
, (266, 1016, 79011.2,   'Operator3')
, (112, 1029, 14869,     'Operator4')
, (112, 996, 22954,      'Operator1')
, (93,   1031, 10568.96, 'Operator5')


DECLARE @TR TABLE 
(
ID varchar(25) NULL , 
Operator1  DECIMAL(18,3) NULL, OC1  DECIMAL(18,3) NULL, Operator2  DECIMAL(18,3) NULL, 
OC2  DECIMAL(18,3) NULL, Operator3  DECIMAL(18,3) NULL, OC3  DECIMAL(18,3) NULL, 
Operator4  DECIMAL(18,3) NULL, OC4  DECIMAL(18,3) NULL, Operator5  DECIMAL(18,3) NULL, 
OC5  DECIMAL(18,3) NULL
)

INSERT @TR
SELECT *
FROM  (
    Select B.*
     From  @OperatorPrice A
     Cross Apply ( values ('Total',FName,Price)
                         ,('Total','OC'+replace(FName,'Operator',''),OperatorID)
                         ,(convert(varchar(25),A.ID),FName,Price)
                         ,(convert(varchar(25),A.ID),'OC'+replace(FName,'Operator',''),OperatorID)
                 ) B (ID,Item,Value)
    Union All
    Select ID='Total'
          ,B.*
     From ( Select Top 50 N=Row_Number() Over (Order By (Select NULL)) 
            From master..spt_values n1 ) A
     Cross Apply ( values (concat('Operator',N),NULL)
                         ,(concat('OC',N),NULL)
                 ) B (Item,Value)
   ) AS SourceTable        
PIVOT  ( sum(Value) FOR Item IN (Operator1, OC1, Operator2, OC2,  
Operator3, OC3, Operator4, OC4,  Operator5, OC5) ) AS PivotTable

Select * from @TR
 Order by try_convert(int,ID)

Returns

enter image description here

答案 1 :(得分:1)

You can use CTE to carry your pivot result set. UNION ALL combine SUM total result set and pivot result.

;with cte as (
SELECT *
FROM  (
    Select A.ID
          ,B.*
     From  @OperatorPrice A
     Cross Apply ( values (FName,Price)
                         ,('OC'+replace(FName,'Operator',''),OperatorID)
                 ) B (Item,Value)
    Union All
    Select ID=(select min(ID) From @OperatorPrice)
          ,B.*
     From ( Select Top 50 N=Row_Number() Over (Order By (Select NULL)) 
            From master..spt_values n1 ) A
     Cross Apply ( values (concat('Operator',N),NULL)
                         ,(concat('OC',N),NULL)
                 ) B (Item,Value)
   ) AS SourceTable        
PIVOT  ( sum(Value) FOR Item IN (Operator1, OC1, Operator2, OC2,  
Operator3, OC3, Operator4, OC4,  Operator5, OC5) ) AS PivotTable
)

INSERT @TR
SELECT 
    NULL,
    SUM(Operator1),
    SUM(OC1),
    SUM(Operator2),
    SUM(OC2),
    SUM(Operator3),
    SUM(OC3),
    SUM(Operator4),
    SUM(OC4),
    SUM(Operator5),
    SUM(OC5) 
FROM CTE
UNION ALL
SELECT ID,Operator1,OC1,Operator2,OC2,Operator3,OC3,Operator4,OC4,Operator5,OC5 
FROM cte

sqlfiddle

相关问题