动态枢轴,具有来自枢轴的最大(日期)

时间:2013-10-22 21:19:04

标签: sql sql-server pivot

我想保持这种一般性,所以如果没问题,我宁愿不使用我的特定数据集。

我的一般例子:我有一张订单很多的客户表。我想要一个数据透视表,显示每个客户每个月(或一般时间范围)有多少订单。假设我想添加一个列,显示该客户最近订购的日期。

所以表格如下:

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

我试图在http://sqlfiddle.com/#!6/cbbad/1处找到一个正在运行的平台,但我显然比我在动态枢轴上的想法更糟糕。

1 个答案:

答案 0 :(得分:2)

如果您想为每位客户添加最新日期,则可以使用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;

请参阅SQL Fiddle with Demo

您的完整代码类似于:

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

请参阅SQL Fiddle with Demo

如果您想按月显示数据(您在上面的结果中显示),那么您可以稍微更改代码以使用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;

SQL Fiddle with Demo。这将得到一个结果:

| 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 |