2012-09-18 47 views
0

可能重複:
SQL Server: How to select all days in a date range even if no data exists for some days日期的選擇範圍,包括那些沒有結果

我真的不知道如何字這個問題,但我會試着解釋。我試圖建立使用查詢類似下面的一些基本的報表:

SELECT COUNT(*) AS count, h_date FROM (SELECT CONVERT(VARCHAR(10), h_time, 102) AS h_date FROM hits h GROUP BY h_date ORDER BY h_date 

這將返回的結果是這樣,我用它來建立一個圖:

8 2012.05.06 
2 2012.05.07 
9 2012.05.09 

正如你所看到的,它缺少第八,因爲那天沒有命中。對於沒有結果的日期,有沒有辦法獲得0的值,還是必須在事實後解析結果並手動添加它們?

+1

什麼版本的SQL Server? –

+0

嘿諾拉,感謝您的鏈接。我想我在搜索時沒有把它說得對。 :) – ZachRabbit

回答

1

您可以使用現有的目錄視圖來導出開始日期和結束日期之間的連續日期範圍。然後你可以只加入你的數據,並且任何缺失的日期將會以0表示。

DECLARE @min SMALLDATETIME, @max SMALLDATETIME; 

SELECT @min = MIN(h_time), @max = MAX(h_time) 
    FROM dbo.hits 
    -- WHERE ? 

-- or if you just want a fixed range: 

-- SELECT @min = '20120101', @max = '20120131'; 

;WITH n(d) AS 
(
    SELECT TOP (DATEDIFF(DAY, @min, @max)+1) 
    DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY [object_id]) - 1, DATEDIFF(DAY, 0, @min)) 
    FROM sys.all_objects ORDER BY [object_id] 
) 
SELECT n.d, [count] = COUNT(h.h_time) 
    FROM n 
    LEFT OUTER JOIN dbo.hits AS h 
    ON h.h_time >= n.d 
    AND h.h_time < DATEADD(DAY, 1, n.d) 
    -- AND --WHERE clause against hits? 
    GROUP BY n.d; 
+0

哇,謝謝!你甚至寫了專欄和表名會去的地方,這對我很有幫助。我希望有一天能成爲像你這樣的SQL嚮導。 :) – ZachRabbit

1

我從來不喜歡使用系統表創建虛擬記錄來加入,但這是一種非常普遍的方法。

我拿了Aaron Bertrand的回答,並改變了公共表格表達式(CTE)來使用遞歸的表達式。它更快,因爲它不必擊中表來執行查詢。不是說以前的版本反正慢。

您需要指定「OPTION(MAXRECURSION 0);」否則會限制返回到默認值(100)的行數。值爲0將返回無限的行。

DECLARE @min SMALLDATETIME, @max SMALLDATETIME; 

--SELECT @min = MIN(h_time), @max = MAX(h_time) 
-- FROM dbo.hits 

SELECT @min = '20120101', @max = '20121231'; 


WITH recursedate(each_date, date_index) AS 
(
SELECT @min, 0 

UNION ALL 
SELECT DATEADD(DAY,date_index+1,@min), date_index+1 
    FROM recursedate 
    WHERE DATEADD(DAY,date_index+1,@min) <= @max 
) 



SELECT recursedate.each_date, [count] = COUNT(h.h_time) 
    FROM recursedate 
    LEFT OUTER JOIN dbo.hits AS h 
    ON --CONVERT(SMALLDATETIME,h.h_time) = recursedate.dates 
    h.h_time >= recursedate.each_date 
    AND h.h_time < DATEADD(DAY, 1, recursedate.each_date) 
    -- AND --WHERE clause against hits? 
    GROUP BY recursedate.each_date 
    OPTION (MAXRECURSION 0); -- The default is 100 so you'll only get 100 dates, 0 is unlimited. 
相關問題