Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Row and column total in dynamic pivot

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.

like image 482
Sokea Avatar asked Jan 30 '15 01:01

Sokea


2 Answers

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

enter image description here

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]' and SELECT @NullToZeroCols += ',ISNULL([Total],0) AS [Total]'.
  • Use ROLLUP instead of CUBE.

enter image description here

2. Show only Column Total

  • Use the code SELECT @cols += ',[Total]' and SELECT @NullToZeroCols += ',ISNULL([Total],0) AS [Total]'.
  • Use ROLLUP instead of CUBE.
  • Change GROUP BY Location,PartCode to GROUP BY PartCode,Location.
  • Instead of ORDER BY CASE WHEN (PartCode=''Total'') THEN 1 ELSE 0 END,PartCode, use WHERE PartCode<>''TOTAL'' ORDER BY PartCode.

enter image description here

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

enter image description here

like image 145
Sarath KS Avatar answered Sep 21 '22 23:09

Sarath KS


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
like image 24
radar Avatar answered Sep 20 '22 23:09

radar