简体   繁体   中英

How to get max and min of columns per row for pivoted table?

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

This is a sample data:

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  
    , MinPrice DECIMAL(18,3) NULL, MaxPrice DECIMAL(18,3) NULL
    , SumCount DECIMAL(18,3) 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
)

The pivot code:

INSERT @TR
SELECT *
FROM  (
    Select B.*
    From  @OperatorPrice A
    Cross Apply ( values  (0,FName,Price)
                     , (0,'OC'+replace(FName,'Operator',''),OperatorID)
                     , (A.ID,'MinPrice', A.Price)
                     , (A.ID,'MaxPrice', A.Price)
                     , (A.ID,'SumCount', A.OperatorId)
                     , (A.ID,FName,Price)
                     , (A.ID,'OC'+replace(FName,'Operator',''),OperatorID)
             ) B (ID,Item,Value)
     Union All
     Select
         ID=0
         , 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 (MinPrice, MaxPrice, SumCount,Operator1, 
      OC1, Operator2, OC2,  
      Operator3, OC3, Operator4, OC4,  Operator5, OC5) ) AS PivotTable

  SELECT * FROM @TR

The above code works perfectly, except MinPrice and MaxPrice are wrong! Currently they are Sum() of Price :

在此输入图像描述

But I need Min() of price and Max() of Price column. So the desired output should looks like this:

在此输入图像描述

How to get Min() of price and Max() of Price column for the row of pivoted table?

Gordon is correct, since you are mixing aggregations, the conditional aggregation may be more performant.

However, by adding a couple of UNION ALLs we can get the desired results

Example

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  
    , MinPrice DECIMAL(18,3) NULL, MaxPrice DECIMAL(18,3) NULL
    , SumCount DECIMAL(18,3) 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  (0,FName,Price)
                        , (0,'OC'+replace(FName,'Operator',''),OperatorID)
                        , (A.ID,'SumCount', A.OperatorId)
                        , (A.ID,FName,Price)
                        , (A.ID,'OC'+replace(FName,'Operator',''),OperatorID)
             ) B (ID,Item,Value)
     Union All 
     Select ID,Item='MinPrice',Value=min(Price) From @OperatorPrice Group By ID
     Union All
     Select ID,Item='MaxPrice',Value=max(Price) From @OperatorPrice Group By ID
     Union All
     Select 0,Item='MinPrice',Value=min(Price) From @OperatorPrice 
     Union All
     Select 0,Item='MaxPrice',Value=max(Price) From @OperatorPrice
     Union All
     Select 0,Item='SumCount',Value=sum(OperatorId) From @OperatorPrice
     Union All
     Select
         ID=0
         , 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 (MinPrice, MaxPrice, SumCount,Operator1, 
      OC1, Operator2, OC2,  
      Operator3, OC3, Operator4, OC4,  Operator5, OC5) ) AS PivotTable

  SELECT * FROM @TR

Returns

在此输入图像描述

Note: I added the Total Min, Max, SumCount for ID 0

You can wrap your entire code with the following:

SELECT CASE WHEN MinPrice IS NOT NULL THEN Mn END MinPrice,
       CASE WHEN MaxPrice IS NOT NULL THEN Mx END MaxPrice,
SumCount , Operator1 , OC1 , Operator2 , OC2 , Operator3 , OC3 ,Operator4 , OC4 ,Operator5 , OC5
 FROM 
 (--This is where your part starts
    SELECT *
    FROM  (
        Select B.*
        From  @OperatorPrice A
        Cross Apply ( values  (0,FName,Price)
                         , (0,'OC'+replace(FName,'Operator',''),OperatorID)
                         , (A.ID,'MinPrice', A.Price)
                         , (A.ID,'MaxPrice', A.Price)
                         , (A.ID,'SumCount', A.OperatorId)
                         , (A.ID,FName,Price)
                         , (A.ID,'OC'+replace(FName,'Operator',''),OperatorID)
                 ) B (ID,Item,Value)
         Union All
         Select
             ID=0
             , 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 (MinPrice, MaxPrice, SumCount,Operator1, 
          OC1, Operator2, OC2,  
          Operator3, OC3, Operator4, OC4,  Operator5, OC5) ) AS PivotTable --This is where your part ends
    ) main
CROSS APPLY 
(
SELECT  MIN(X.t) Mn , MAX(X.t) Mx 
FROM 
    (
    VALUES (Operator1) , (Operator2) , (Operator3) , (Operator4) , (Operator5)
    ) x (t)
) Q

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM