Reputation: 2475
I want to keep this general so if it's ok, I'd prefer to not use my specific data set.
My general example: I have a table of customers who have many orders. I want a pivot table that shows how many orders each customer has had in each month (or general time frame). Suppose I want to add a single column that shows the date for that customers most recent order.
So the table will look like:
CustomerID - January - February - March - April - May - MostRecentOrder
0001 - 2 - 3 - 1 - 1 - 1 - 2013/5/18
0002 - 1 - 0 - 1 - 0 - 1 - 2013/5/06
0003 - 0 - 1 - 4 - 1 - 2 - 2013/5/11
0004 - 2 - 0 - 0 - 1 - 0 - 2013/4/28
I tried to get a working sqlfiddle up at http://sqlfiddle.com/#!6/cbbad/1 but I'm apparently worse than I thought at Dynamic pivots in general.
Upvotes: 1
Views: 1657
Reputation: 247720
If you want to include the most recent date for each customer, then you can use max(orderdate) over(partition by customerId)
:
select customer.CustomerID,
o.OrderDate,
max(o.orderdate) over(partition by customer.customerid) mostrecentorder
from Customers as customer
join Orders as o
on customer.CustomerID = o.customerid;
See SQL Fiddle with Demo.
Your full code would be similar to:
declare @start DATE = '2012-01-01';
declare @end DATE = DATEADD(dd,-(DAY(GETDATE())-1),GETDATE());
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
with months (dateList)
AS
(
SELECT @start
UNION ALL
SELECT DATEADD(month,1,dateList)
from months
where DATEADD(month,1,dateList)<=@end
)
select dateList
into #tempDates
from months
option (maxrecursion 0);
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(convert(varchar(10), datelist, 120))
from #tempDates
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = '
select *
from
(
select customer.CustomerID,
o.OrderDate,
max(o.orderdate) over(partition by customer.customerid) mostrecentorder
from Customers as customer
join Orders as o
on customer.CustomerID = o.customerid
) x
pivot
(
Count(OrderDate)
for OrderDate in ('+ @cols + ')
)y'
execute sp_executesql @query
See SQL Fiddle with Demo.
If you want to show the data by month (which you are showing in your result above), then you can alter the code slightly to use DATENAME:
declare @start DATE = '2012-01-01';
declare @end DATE = DATEADD(dd,-(DAY(GETDATE())-1),GETDATE());
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
with months (dateList)
AS
(
SELECT @start
UNION ALL
SELECT DATEADD(month,1,dateList)
from months
where DATEADD(month,1,dateList)<=@end
)
select dateList
into #tempDates
from months
option (maxrecursion 0);
select @cols = STUFF((SELECT ',' + QUOTENAME(mth)
from
(
select datepart(month, datelist) so, datename(month, datelist) mth
from #tempDates
) d
group by so, mth
order by so, mth
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = '
select customerId, '+@cols+', mostrecentorder
from
(
select customer.CustomerID,
datename(month, o.OrderDate) orderDate,
max(o.orderdate) over(partition by customer.customerid) mostrecentorder
from Customers as customer
join Orders as o
on customer.CustomerID = o.customerid
) x
pivot
(
Count(OrderDate)
for OrderDate in ('+ @cols + ')
)y'
execute sp_executesql @query;
See SQL Fiddle with Demo. This will give a result:
| CUSTOMERID | JANUARY | FEBRUARY | MARCH | APRIL | MAY | JUNE | JULY | AUGUST | SEPTEMBER | OCTOBER | NOVEMBER | DECEMBER | MOSTRECENTORDER |
|------------|---------|----------|-------|-------|-----|------|------|--------|-----------|---------|----------|----------|----------------------------|
| 3 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | May, 03 2013 00:00:00+0000 |
| 2 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | May, 13 2013 00:00:00+0000 |
| 1 | 1 | 2 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | May, 23 2013 00:00:00+0000 |
Upvotes: 2