动态 SQL 滚动 12 个月数据透视

Posted

技术标签:

【中文标题】动态 SQL 滚动 12 个月数据透视【英文标题】:Dynamic SQL Rolling 12 Months Pivot 【发布时间】:2021-08-09 13:03:53 【问题描述】:

我是动态 SQL 的新手。我有下表:

CustName Date Hours
First 01/01/2021 12
Second 01/01/2021 10
Second 05/02/2021 1
Second 10/11/2021 14

我正在尝试为过去 12 个月的总小时数制作一个滚动日历 Pivot。

这是我做的代码:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

    select @cols = STUFF(
    (SELECT distinct ',' + QUOTENAME(DATENAME(mm,Date) + ' of ' 
    + DATENAME(year,Date)) AS months_ago
          FROM [TimeEntryList]  
          WHERE Date > DATEADD(year, -1, 
    DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1))
    FOR XML PATH(''), TYPE
    ).value('.', 'NVARCHAR(MAX)') 
,1,1,'')


 set @query = 'SELECT CustName, ' + @cols + ' 
 from ( select 
   [CustName], 
   datename(mm,[Date])+'' of ''+datename(year,[Date])AS 
   months_ago, [Hours] AS NetQty 
   from [TimeEntryList] 
    WHERE [Date] > DATEADD(year, -1, 
  DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1))
 ) as source 
 pivot 
 ( 
 sum(NetQty) For months_ago  in (' + @cols + ')
 ) as PivotTable'

execute sp_executesql @query;

这“有点”我想要的效果,但列不是从当前日期倒序排列的。

我希望它从当前月份开始倒数。因此,如果这个月是 8 月,那将是:

CustName Sep 2020 .... months August 2021
First 12 14
Second 3 12

有没有一种好方法可以从 Dynamic SQL 中的当前月份开始,然后返回 12 个月?

我试过'order by months_ago desc'等,但这不起作用

【问题讨论】:

【参考方案1】:

您只需要添加一个WHERE 过滤器。这需要在查询的两个部分中。

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX);

SET @cols = STUFF(
    (SELECT ',' + QUOTENAME(DATENAME(mm, EOMONTH(Date)) + ' of ' + DATENAME(year, EOMONTH(Date))) AS months_ago
    FROM [TimeEntryList]  
    WHERE [Date] > DATEADD(year, -1, DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1))
    GROUP BY EOMONTH(Date)
    ORDER BY EOMONTH(Date)
    FOR XML PATH(''), TYPE
    ).value('text()[1]', 'NVARCHAR(MAX)') 
,1,1,'');

SET @query = '
SELECT
  CustName,
  ' + @cols + ' 
from (
  select 
    [CustName], 
    datename(mm,[Date])+'' of ''+datename(year,[Date])AS months_ago, [Hours] AS 
    NetQty 
   from [TimeEntryList]
   WHERE [Date] > DATEADD(year, -1, DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1))
 ) as source 
pivot 
  ( 
   sum(NetQty) For months_ago  in (' + @cols + ')
  ) as PivotTable;
';

execute sp_executesql @query;

您甚至可以传递开始日期参数,如下所示:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @dateFrom datetime;

SET @dateFrom = DATEADD(year, -1, DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1));

SET @cols = STUFF(
    (SELECT ',' + QUOTENAME(DATENAME(mm,EOMONTH(Date)) + ' of ' + DATENAME(year,EOMONTH(Date)) AS months_ago
    FROM [TimeEntryList]  
    WHERE [Date] > @dateFrom
    GROUP BY EOMONTH(Date)
    ORDER BY EOMONTH(Date)
    FOR XML PATH(''), TYPE
    ).value('text()[1]', 'NVARCHAR(MAX)') 
,1,1,'');

SET @query = '
SELECT
  CustName,
  ' + @cols + ' 
from (
  select 
    [CustName], 
    datename(mm,[Date])+'' of ''+datename(year,[Date])AS months_ago, [Hours] AS 
    NetQty 
   from [TimeEntryList]
   WHERE [Date] > @dateFrom
 ) as source 
pivot 
  ( 
   sum(NetQty) For months_ago  in (' + @cols + ')
  ) as PivotTable;
';

execute sp_executesql
    @query
    N'@dateFrom datetime',
    @dateFrom = @dateFrom;

【讨论】:

啊-谢谢。出于某种原因,我得到的 'QUOTENAME' 不是内置函数。如果我将它括在括号中,它会修复它,但报告只是执行并且不显示数据。 我编辑了我的答案,谢谢!我认为主要问题是,我试图将最后一列作为当前月份,列按月向后滚动 我认为归结为“动态”部分的排序。我知道如何在常规 SQL 中按日期排序,但是对于这个动态示例,我认为我需要尝试在“months_ago”上进行排序,但这是行不通的。也许我需要先创建一个临时数据透视表,然后使用动态 SQL ...也许 .. 有点新。 谢谢! - 我创建了一个here 如您所见,2021 年 4 月首先出现。 OK 为你解决了这个问题dbfiddle.uk/…

以上是关于动态 SQL 滚动 12 个月数据透视的主要内容,如果未能解决你的问题,请参考以下文章

c# 在 SQL 动态数据透视字符串中添加变量

SQL 数据透视表动态

SQL 动态数据透视表列顺序

SQL Server 数据库中的动态数据透视

SQL Server:多列的动态数据透视

SQL Server - 动态数据透视表 - SQL 注入