0

我正在根据日期对表中的数据进行透视,但需要为没有数据的日期返回 NULL。

[dbo].[Metrics] 中的数据:

指标

我正在执行的动态数据透视 SQL:

DECLARE @cols NVARCHAR(1000);
SELECT @cols = 
STUFF((SELECT N'],[' + month_day
         FROM (SELECT DISTINCT RIGHT(CONVERT(NCHAR(10), [Date], 126), 2)
                 FROM [Metrics]) AS O(month_day)
         ORDER BY month_day
          FOR XML PATH('')
       ), 1, 2, '') + N']';

DECLARE @sql NVARCHAR(2000);

SET @sql =
N'SELECT [Key], ' + @cols +
N'  FROM (SELECT [Key], ' +
N'               RIGHT(CONVERT(NCHAR(10), [Date], 126), 2) AS month_day, ' +
N'               [Value] ' +
N'          FROM [Metrics]) AS O ' +
N'PIVOT ' +
N'(SUM([Value]) FOR month_day IN (' + @cols + N')) AS P;';

EXECUTE(@sql);

...以及动态 SQL 返回的结果集:

透视数据

如您所见,由于我没有每月每一天的数据,因此根本不会返回那些日子的列。如何让它为每个单元格返回 NULL 列 10-23 和 28-31?无论实际月份如何,它都应返回第 1-31 列(例如,即使给定月份少于 31 天,也应返回 31 列)。

任何帮助表示赞赏。

4

1 回答 1

2

然后你真的不需要动态生成这些列,因为你总是希望它们从 1 到 31。更简单的方法是在你的数据透视表上硬编码这些值,真的。无论如何,这是您可以动态定义列并且仍然可以整天使用的方式:

SELECT @cols = 
STUFF((SELECT N'],[' + CAST(number AS VARCHAR(2))
         FROM (SELECT DISTINCT number
               FROM master..[spt_values] 
               WHERE number BETWEEN 1 AND 31) AS O(number)
         ORDER BY number
          FOR XML PATH('')
       ), 1, 2, '') + N']';

您真正应该使用的版本是:

SELECT *
FROM (SELECT [Key], 
             RIGHT(CONVERT(NCHAR(10), [Date], 126), 2) AS month_day, 
             [Value] 
      FROM [Metrics]) AS O 
PIVOT (SUM([Value]) FOR month_day IN ([01],[02],[03],[04],[05],[06],[07],[08],[09],
                                      [10],[11],[12],[13],[14],[15],[16],[17],[18],
                                      [19],[20],[21],[22],[23],[24],[25],[26],[27],
                                      [28],[29],[30],[31])) AS P;
于 2013-02-27T19:55:35.587 回答