使用 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 解决它,但我对此感到困惑。
将 cte
和 union all
与 group 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;
我有一个存储过程:
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 解决它,但我对此感到困惑。
将 cte
和 union all
与 group 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 thanISNULL
, because this tells you if the column was actually grouped, and you can see the difference between that an actualNULL
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;