问题
In SQL Server 2008, I have a table (tblStock) with 3 columns:
- PartCode (NVARCHAR (50))
- StockQty (INT)
- Location (NVARCHAR(50))
some example data below:
PartCode StockQty Location
......... ......... .........
A 10 WHs-A
B 22 WHs-A
A 1 WHs-B
C 20 WHs-A
D 39 WHs-F
E 3 WHs-D
F 7 WHs-A
A 9 WHs-C
D 2 WHs-A
F 54 WHs-E
How to create procedure to get the result as below?
PartCode WHs-A WHs-B WHs-C WHs-D WHs-E WHs-F Total
........ ..... ..... ..... ...... ..... ..... .....
A 10 1 9 0 0 0 20
B 22 0 0 0 0 0 22
C 20 0 0 0 0 0 20
D 2 0 0 0 0 39 41
E 0 0 0 3 0 0 3
F 7 0 0 0 54 0 61
Total 61 1 9 3 54 39 167
Your help is much appreciated, thanks.
回答1:
SAMPLE TABLE
SELECT * INTO #tblStock
FROM
(
SELECT 'A' PartCode, 10 StockQty, 'WHs-A' Location
UNION ALL
SELECT 'B', 22, 'WHs-A'
UNION ALL
SELECT 'A', 1, 'WHs-B'
UNION ALL
SELECT 'C', 20, 'WHs-A'
UNION ALL
SELECT 'D', 39, 'WHs-F'
UNION ALL
SELECT 'E', 3, 'WHs-D'
UNION ALL
SELECT 'F', 7, 'WHs-A'
UNION ALL
SELECT 'A', 9, 'WHs-C'
UNION ALL
SELECT 'D', 2, 'WHs-A'
UNION ALL
SELECT 'F', 54, 'WHs-E'
)TAB
Get the columns for dynamic pivoting and replace NULL
with zero
DECLARE @cols NVARCHAR (MAX)
SELECT @cols = COALESCE (@cols + ',[' + Location + ']', '[' + Location + ']')
FROM (SELECT DISTINCT Location FROM #tblStock) PV
ORDER BY Location
-- Since we need Total in last column, we append it at last
SELECT @cols += ',[Total]'
--Varible to replace NULL with zero
DECLARE @NulltoZeroCols NVARCHAR (MAX)
SELECT @NullToZeroCols = SUBSTRING((SELECT ',ISNULL(['+Location+'],0) AS ['+Location+']'
FROM (SELECT DISTINCT Location FROM #tblStock)TAB
ORDER BY Location FOR XML PATH('')),2,8000)
SELECT @NullToZeroCols += ',ISNULL([Total],0) AS [Total]'
You can use CUBE
to find row and column total and replace NULL
with Total
for the rows generated from CUBE
.
DECLARE @query NVARCHAR(MAX)
SET @query = 'SELECT PartCode,' + @NulltoZeroCols + ' FROM
(
SELECT
ISNULL(CAST(PartCode AS VARCHAR(30)),''Total'')PartCode,
SUM(StockQty)StockQty ,
ISNULL(Location,''Total'')Location
FROM #tblStock
GROUP BY Location,PartCode
WITH CUBE
) x
PIVOT
(
MIN(StockQty)
FOR Location IN (' + @cols + ')
) p
ORDER BY CASE WHEN (PartCode=''Total'') THEN 1 ELSE 0 END,PartCode'
EXEC SP_EXECUTESQL @query
- Click here to view result
RESULT
NOTE : If you want NULL
instead of zero
as values, use @cols
instead of @NulltoZeroCols
in dynamic pivot code
EDIT :
1. Show only Row Total
- Do not use the code
SELECT @cols += ',[Total]'
andSELECT @NullToZeroCols += ',ISNULL([Total],0) AS [Total]'
. - Use
ROLLUP
instead ofCUBE
.
2. Show only Column Total
- Use the code
SELECT @cols += ',[Total]'
andSELECT @NullToZeroCols += ',ISNULL([Total],0) AS [Total]'
. - Use
ROLLUP
instead ofCUBE
. - Change
GROUP BY Location,PartCode
toGROUP BY PartCode,Location
. - Instead of
ORDER BY CASE WHEN (PartCode=''Total'') THEN 1 ELSE 0 END,PartCode
, useWHERE PartCode<>''TOTAL'' ORDER BY PartCode
.
UPDATE : To bring PartName
for OP
I am updating the below query to add PartName
with result. Since PartName
will add extra results with CUBE
and to avoid confusion in AND
or OR
conditions, its better to join the pivoted result with the DISTINCT
values in your source table.
DECLARE @query NVARCHAR(MAX)
SET @query = 'SELECT P.PartCode,T.PartName,' + @NulltoZeroCols + ' FROM
(
SELECT
ISNULL(CAST(PartCode AS VARCHAR(30)),''Total'')PartCode,
SUM(StockQty)StockQty ,
ISNULL(Location,''Total'')Location
FROM #tblStock
GROUP BY Location,PartCode
WITH CUBE
) x
PIVOT
(
MIN(StockQty)
FOR Location IN (' + @cols + ')
) p
LEFT JOIN
(
SELECT DISTINCT PartCode,PartName
FROM #tblStock
)T
ON P.PartCode=T.PartCode
ORDER BY CASE WHEN (P.PartCode=''Total'') THEN 1 ELSE 0 END,P.PartCode'
EXEC SP_EXECUTESQL @query
- Click here to view result
回答2:
you need to use case based aggregation
to pivot the data
To get the total
row use union
In case the Location
values are not known in advance, you need to construct a dynamic query
you can also use pivot
keyword to do the same.
select partCode,
sum( case when Location='WHs-A' then StockQty
else 0 end
) as 'Whs-A',
sum( case when Location='WHs-B' then StockQty
else 0 end
) as 'Whs-B',
sum(StockQty) as 'Total'
from tblStock
group by partCode
union all
select 'Total' as 'partCode',
sum( case when Location='WHs-A' then StockQty
else 0 end ) as 'Whs-A',
sum( case when Location='WHs-B' then StockQty
else 0 end) as 'Whs-B',
sum(StockQty) as 'Total'
from tblStock
来源:https://stackoverflow.com/questions/28227924/row-and-column-total-in-dynamic-pivot