【问题标题】:Rolling calendar pivot in sql server?在sql server中滚动日历枢轴?
【发布时间】:2016-02-25 14:49:21
【问题描述】:

我已经设法为自己构建了一个漂亮的小 T-SQL 语句,它将调度信息转变成每月的列。

SELECT *
FROM 
(
    SELECT 
    t1.customer_code,
    t1.part_number,
    LEFT(DATENAME(month, [formatted_date]),3) as [Month],
    t1.quantity as [quantity] FROM FORECAST_VIEW as t1

    where
        quantity <> 0 
        and formatted_date >= DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)  

) as p
pivot
(
    sum(quantity)
    for [Month] in (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec)
) as p
order by customer_code, part_number

这会产生带有列的输出

customer_code, part_number, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec

并汇总每个月所需的 part_number 数量。

这很好用,并且在报告中产生了奇迹,但是如果我可以让月份列从当前月份开始并按顺序排列 12 个月,那么这将是锦上添花。

问题是我不知道该怎么做。

如果我今天运行它,输出将是

customer_code, part_number, Nov, Dec, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct

有人有什么建议吗?

谢谢

编辑 我刚刚想到的事情,如果我找不到解决方案但它很难看,我不会排除。 我可以将整个 T-SQL 语句放在一个 IF 块中

IF LEFT(DATENAME(month, GETDATE()),3) = 'Nov'
BEGIN
SELECT *
FROM 
(
    ...
) as p
pivot
(   sum(quantity)
    for [Month] in (Nov, Dec, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct)
) as p
order by customer_code, part_number
END

重复 12 次并调整基准月份。

【问题讨论】:

  • 您可以转入 datediff(m..) 列 (m0 .. m11) 并在客户端使列标题动态化(并填写正确的月份名称)。或者,如果您需要具有正确列名的 SQL 结果,则必须执行动态 SQL(在存储过程中)。

标签: sql-server database tsql pivot


【解决方案1】:

您必须使用动态 SQL 来实现这一点。

首先您必须按正确的顺序获取月份名称:

Declare @cols nvarchar(max);

with list as (
    Select n, m = Left(DATENAME(month, DATEADD(month, n, getdate())), 3)
    From (values (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11)) as x(n)
)
Select @cols = STUFF((
        Select ', ' + QUOTENAME(m) 
        From list 
        Order By n
        FOR XML PATH(''), TYPE
    ).value('.', 'NVARCHAR(MAX)') 
,1,1,'');

@cols 值将是:[Nov], [Dec], [Jan], [Feb], [Mar], [Apr], [May], [Jun], [Jul], [Aug], [Sep], [Oct]

然后您可以将您的查询与@cols 混合并执行它:

Declare @sql nvarchar(max);

Set @sql = '
    SELECT *
    FROM 
    (
    SELECT 
        t1.customer_code,
        t1.part_number,
        LEFT(DATENAME(month, [formatted_date]),3) as [Month],
        t1.quantity as [quantity] FROM FORECAST_VIEW as t1   
        where
            quantity <> 0 
            and formatted_date >= DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)  
    ) as p
    pivot
    (   sum(quantity)
        for [Month] in ('+@cols+')
    ) as p
    order by customer_code, part_number;

EXEC sp_executesql @sql;

如果您真的不需要动态列名,并且可以在代码中使用列名(例如 12 个月前、11 个月前、...直到上个月的 [0], [1], ... , [11])来处理它,那么您可以使用这个查询:

SELECT *
FROM 
(
    SELECT 
    t1.customer_code,
    t1.part_number,
    (12 - DATEPART(month, x) + DATEPART(month, getdate())) % 12 as [Month],
    t1.quantity as [quantity] FROM FORECAST_VIEW as t1

    where
        quantity <> 0 
        and formatted_date >= DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)      
) as p
pivot
(
    sum(quantity)
    for [Month] in ([0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11])
) as p
order by customer_code, part_number

(12 - DATEPART(month, x) + DATEPART(month, getdate())) % 12 将返回如下值:

Date                    | Month
2015-11-23 16:11:57.860 | 0
2015-10-23 16:11:57.860 | 1
2015-09-23 16:11:57.860 | 2
2015-08-23 16:11:57.860 | 3
2015-07-23 16:11:57.860 | 4
2015-06-23 16:11:57.860 | 5
2015-05-23 16:11:57.860 | 6
2015-04-23 16:11:57.860 | 7
2015-03-23 16:11:57.860 | 8
2015-02-23 16:11:57.860 | 9
2015-01-23 16:11:57.860 | 10
2014-12-23 16:11:57.860 | 11

【讨论】:

  • 非常感谢。这正是我一直在寻找的。您基本上所做的是获取当前日期,然后添加 0,然后 1,然后 2 等以获取其余月份。我认为应该这样做,但我不知道解决它的语法
  • 是的。在第二个查询中它稍微复杂一点,因为 11 是 12 个月前,依此类推。这就是我使用模数 (%) 的原因。首先,我只是从 getdate 中删除 X 月并获得所有 12 个月。
猜你喜欢
  • 2010-12-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-30
  • 1970-01-01
  • 1970-01-01
  • 2022-11-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多