2014-02-19 23 views
0

我有一個包含每日人員報告的MS SQL Server 2012表。每天包含一個人的最多1條記錄,並將該日存儲爲DateTime,並將時間部分設置爲「00:00:00.000」。示例:'2014-01-30 00:00:00.000'通過SQL查詢獲取某個日期沒有值的項目

+-----------+-------------------------+----------------+ 
| Person id | Date     | Report content | 
+-----------+-------------------------+----------------+ 
|   1 | 2014-01-29 00:00:00.000 | Account stuff | 
+-----------+-------------------------+----------------+ 
|   2 | 2014-01-29 00:00:00.000 | Coaching stuff | 
+-----------+-------------------------+----------------+ 
|   2 | 2014-01-30 00:00:00.000 | Still coaching | 
+-----------+-------------------------+----------------+ 

所有人員都存儲在一個單獨的表中。

如何從數據庫中選擇一段時間內缺少記錄的人員?即使該人報告了30份報告,但1份報告缺失,他也應該在結果中。可能會發生,每個人都錯過了一個或多個報告日。這就是爲什麼我無法比較人與人之間的關係。

例如,我想知道誰在1月1日至2月1日之間沒有創建他/她的報告。

+1

的SQL Server版本? –

+0

指定SQL Server版本:2012 – Germstorm

+1

如果他們沒有記錄,您希望如何選擇它們?你有另一張桌子給所有的人嗎? –

回答

2

OK以及如何對類似

DECLARE @StartDate DATETIME = '01 Jan 2014', 
     @EndDate DATETIME = '01 Feb 2014' 

;WITH Dates AS (
    SELECT @StartDate RunDate 
    UNION ALL 
    SELECT RunDate + 1 
    FROM Dates 
    WHERE RunDate + 1 <= @EndDate 
) 
, PersonIDs AS (
    SELECT DISTINCT 
      PersonID 
    FROM MyTable 
) 
, PersonDates AS (
    SELECT RunDate, 
      PersonID 
    FROM Dates, 
      PersonIDs 
) 
SELECT * 
FROM PersonDates pd LEFT JOIN 
     MyTable mt ON pd.RunDate = mt.[Date] AND pd.PersonID = mt.PersonID 
WHERE mt.PersonID IS NULL 
OPTION (MAXRECURSION 0) 

編輯:

正如一個簡短的過圖。

使用CTE結構,我使用遞歸性質來生成日期列表。

然後,我檢索了一個不同的清單PersonID s(如果您有一個Person表,這也可能有幫助,或活動清單或MustReportList等)。

之後,我們使用笛卡爾產品來生成由PersonID生成的日期列表,以計算所有日期的所有人員。

然後,我們將連接留在原始表上,並使用IS NULL確定缺失的條目。

最後,OPTION (MAXRECURSION)是爲了確保一旦你超過MAX RECURSION LEVEL,我們不會得到一個異常(基本上告訴SQL SERVER你知道你在做什麼)。

希望有所幫助。

+0

這很有幫助,非常感謝。這將是很好,雖然有一些解釋,因爲代碼是高層次:) – Germstorm

+1

@Germstorm,增加了一些explenations。 –

+0

幫了很多,謝謝! – Germstorm

1

試試這個:

SELECT DISTINCT PersonID 
FROM 
[Table] A 
WHERE 
NOT EXISTS 
(
SELECT 1 FROM [Table] 
WHERE 
    [PersonID] = A.[PersonID] 
    AND TRY_CAST([Date] AS DATE) BETWEEN TRY_CAST('January 1, 2014' AS DATE) AND TRY_CAST('February 1, 2014' AS DATE) 
) 
+1

我更喜歡ISO 8601的日期格式https://xkcd.com/1179/例如BETWEEN'2014-01-01T00:00:00'和'2014-02-01T00:00:00' – Ruskin

+0

這取決於用戶。上述格式更容易理解,並有一個共同的解釋。其他格式可能會導致不同區域的用戶混淆。dd-mm-yy和其他格式通常會將用戶與其他格式的linke mm-dd-yy混淆。 –

0
Select personid from your_table not in 
(
    Select personid from your_table 
    Where date between start_date and end_date 
) 
相關問題