使用 rollup 通过分组计算总计

Use rollup to calculate grand totals with grouping

我有一个存储过程:

ALTER PROCEDURE GetReportData
AS
BEGIN
    SELECT 
        LOC.SubCompanyNameVN,
        LOC.BranchName,
        COUNT(LOC.BranchCode) as Total,

        ----------- Not Processed Yet
        SUM (CASE WHEN SS.Status IN (5, 6) THEN 1 ELSE 0 END) AS CountNotProcessedYet,
        
        ----------- Processing
        SUM (CASE WHEN SS.Status IN (3) THEN 1 ELSE 0 END) AS CountProcessing

    FROM 
        DBO.WorkingSession AS SS
    JOIN 
        DBO.Location AS LOC ON SS.LocationID = LOC.LocationID 
                            AND SS.BranchCode = LOC.BranchCode
    JOIN 
        DBO.Status AS ST ON SS.Status = ST.ID
    GROUP BY 
        LOC.SubCompanyNameVN, LOC.BranchName
    ORDER BY 
        LOC.SubCompanyNameVN
END

结果:

SubCompanyNameVN BranchName Total CountNotProcessedYet CountProcessing
Vùng 1 HNI_01 5 3 2
Vùng 1 HNI_02 15 5 10
Vùng 1 HNI_07 12 6 6
Vùng 2 HCM_01 86 50 36
Vùng 2 HCM_03 35 17 18

但现在我希望我的结果是:

SubCompanyOrBranchName Total CountNotProcessedYet CountProcessing
Vùng 1 32 14 18
HNI_01 5 3 2
HNI_02 15 5 10
HNI_07 12 6 6
Vùng 2 121 67 54
HCM_01 86 50 36
HCM_03 35 17 18

如何按 SubCompanyNameVN 列(Group By SubCompanyNameVN)对结果进行分组,以像上面那样计算总数 table?我已经研究过,我认为我可以用 ROLLUP 解决它,但我对此感到困惑。

cteunion allgroup by

结合使用
With cte AS ( 
     SELECT 
        LOC.SubCompanyNameVN,
        LOC.BranchName,
        COUNT(LOC.BranchCode) as Total,

        ----------- Not Processed Yet
        SUM (CASE WHEN SS.Status IN (5, 6) THEN 1 ELSE 0 END) AS CountNotProcessedYet,
        
        ----------- Processing
        SUM (CASE WHEN SS.Status IN (3) THEN 1 ELSE 0 END) AS CountProcessing,
        ROW_NUMBER() OVER(PARTITION BY LOC.SubCompanyNameVN ORDER BY LOC.SubCompanyNameVN) AS seq

    FROM 
        DBO.WorkingSession AS SS
    JOIN 
        DBO.Location AS LOC ON SS.LocationID = LOC.LocationID 
                            AND SS.BranchCode = LOC.BranchCode
    JOIN 
        DBO.Status AS ST ON SS.Status = ST.ID
    GROUP BY 
        LOC.SubCompanyNameVN, LOC.BranchName)
        
select SubCompanyNameVN,Total,CountNotProcessedYet,CountProcessing
from
(select SubCompanyNameVN,
       sum(Total) As Total,
       sum(CountNotProcessedYet) As CountNotProcessedYet,
       sum(CountProcessing) As CountProcessing,
       dense_rank()over(order by SubCompanyNameVN) As rnk
   from cte
   group by SubCompanyNameVN
   union all
   select BranchName,
       Total,
       CountNotProcessedYet,
       CountProcessing,
       dense_rank()over(order by SubCompanyNameVN) As rnk
   from cte) T
order by rnk,SubCompanyNameVN desc

演示在 db<>fiddle

我最终通过 ROLLUP 找到了解决方案,这是我需要的:

SELECT 
        (CASE 
            WHEN
                BranchName is NULL
                    THEN SubCompanyNameVN ELSE BranchName
        END) AS SubCompanyOrBranchName,
        Total, CountNotProcessedYet, PercentNotProcessedYet, CountProcessing, PercentProcessing,
        CountProcessedIn5Days, PercentProcessedIn5Days, CountProcessedOver5Days, PercentProcessedOver5Days
    FROM
    (
        SELECT 
            LOC.SubCompanyNameVN,
            LOC.BranchName,
            COUNT(LOC.BranchCode) as Total,
            ----------- Not Processed Yet
            SUM (CASE WHEN SS.Status IN (5, 6) THEN 1 ELSE 0 END) AS CountNotProcessedYet,
        
            ----------- Processing
            SUM (CASE WHEN SS.Status IN (3) THEN 1 ELSE 0 END) AS CountProcessing

        FROM DBO.WorkingSession AS SS
        JOIN DBO.Location AS LOC ON SS.LocationID = LOC.LocationID AND SS.BranchCode = LOC.BranchCode
        JOIN DBO.Status AS ST ON SS.Status = ST.ID
        GROUP BY ROLLUP(LOC.SubCompanyNameVN, LOC.BranchName)
        ORDER BY LOC.SubCompanyNameVN, LOC.BranchName OFFSET 1 ROWS
    ) T

除了 ROLLUP,您还可以使用 GROUPING SETS,这让您可以更灵活地选择所需的确切汇总。

It's better to use the GROUPING() function rather than ISNULL, because this tells you if the column was actually grouped, and you can see the difference between that an actual NULL

 SELECT 
     CASE WHEN GROUPING(LOC.BranchName) = 0
       THEN LOC.BranchName
       ELSE LOC.SubCompanyNameVN
       END AS SubCompanyOrBranchName,
     COUNT(LOC.BranchCode) as Total,

     ----------- Not Processed Yet
     SUM (CASE WHEN SS.Status IN (5, 6) THEN 1 ELSE 0 END) AS CountNotProcessedYet,
     
     ----------- Processing
     SUM (CASE WHEN SS.Status IN (3) THEN 1 ELSE 0 END) AS CountProcessing

 FROM 
     DBO.WorkingSession AS SS
 JOIN 
     DBO.Location AS LOC ON SS.LocationID = LOC.LocationID 
                         AND SS.BranchCode = LOC.BranchCode
 JOIN 
     DBO.Status AS ST ON SS.Status = ST.ID
 GROUP BY GROUPING SETS (
     (LOC.SubCompanyNameVN, LOC.BranchName),
     (LOC.SubCompanyNameVN)
 )
 ORDER BY 
     LOC.SubCompanyNameVN,
     GROUPING(LOC.BranchName) DESC, -- put the totalled rows first
     LOC.BranchName;