2013-02-27 33 views
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的回报:

Pivot data

由于哟你可以看到,因为我没有每月的每一天的数据,它根本就不会返回那些日子的列。我怎样才能让它返回每个单元格为NULL的列10-23和28-31?无论实际月份如何,它都应该返回第1-31列(例如,即使在特定月份中少于31天的情况下也是31列)。

任何帮助表示赞赏。

回答

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; 
+0

嗨Lamak,用于尖端的感谢。我非常专注于使用动态SQL,我并没有停下来想,也许我不需要。我实现了你的第二个解决方案,它的工作几乎完美,除了1-9天似乎没有返回值。我想这与RIGHT()函数有关,而且这个前导零是正确的? – 2013-02-27 20:04:48

+0

@PhillipCopley是的,对不起,你对此是正确的。更新了我的答案。 – Lamak 2013-02-27 20:08:36