0

I'm struggling with an error while making a dynamic pivot table

The source data is

JobID | SalesForMonth | YearMonth
7734  |   400         | 2016-12
7734  |   350         | 2017-01
8540  |   444         | 2016-12
8540  |   300         | 2017-01

and aiming for

JobID | 2016-12 | 2017-01
7734  |   400   |   350
8540  |   444   |   300

and I've tried to use a query I found on here to create the column headers. But must admit I don't really understand the 'For XML' line and getting a syntax error there on line 6

DECLARE 
@cols AS NVARCHAR(MAX),
@query  AS NVARCHAR(MAX)
SELECT @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(YearMonth) 
                FROM v_JobSalesByMonth
        FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'')

SELECT @query = 
'SELECT * FROM
(SELECT JobID, YearMonth, SalesForMonth
FROM v_JobSalesByMonth) X
PIVOT 
(
(JobID, SalesForMonth)
for [YearMonth] in (' + @cols + ')
) P'

I'd also like to stick in a 'total sales' for the jobID column

Any help would be much appreciated

  • You got an error in your pivot. You need to change `(JobID, SalesForMonth)` to `sum(SalesForMonth)`. Here is a [demo](http://data.stackexchange.com/stackoverflow/query/618823). Then if you want a total by JobId you can use `sum(SalesForMonth) over...()` - here is another demo - http://data.stackexchange.com/stackoverflow/query/618826 – Taryn Jan 23 '17 at 13:26
  • SQL Server 2016 added the `STRING_AGG` function – Panagiotis Kanavos Jan 23 '17 at 13:29

1 Answers1

0
Declare @SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(YearMonth) From v_JobSalesByMonth  Order by 1 For XML Path('')),1,1,'') 
Select  @SQL = '
Select [JobID],[TotalSales],' + @SQL + '
From (
        Select JobID
              ,TotalSales = sum(SalesForMonth) over (Partition By JobID)
              ,YearMonth
              ,SalesForMonth
         From v_JobSalesByMonth A
     ) A
 Pivot (sum(SalesForMonth) For [YearMonth] in (' + @SQL + ') ) p'
Exec(@SQL);

Returns

enter image description here

EDIT - Dynamically Create View

Since you can't have dynamic SQL in a view, you could have job scheduled (daily or monthly) to drop and re-create the view.

if object_id('vw_SalesByMonth','v') is not null
drop view vw_SalesByMonth;


Declare @SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(YearMonth) From Yourtable  Order by 1 For XML Path('')),1,1,'') 
Select  @SQL = '
Create View vw_SalesByMonth
AS

Select [JobID],[TotalSales],' + @SQL + '
From (
        Select JobID
              ,TotalSales = sum(SalesForMonth) over (Partition By JobID)
              ,YearMonth
              ,SalesForMonth
         From YourTable A
     ) A
 Pivot (sum(SalesForMonth) For [YearMonth] in (' + @SQL + ') ) p'
Exec(@SQL);

Select * from vw_SalesByMonth
John Cappelletti
  • 79,615
  • 7
  • 44
  • 66