2011-10-22 89 views
2

我有一個BreakdownLog表具有以下的列:日期範圍交叉口

EquipmentID, ProblemID, BreakdownDate, IssueFixedDate 

每個設備可以有多個故障,更重要的是,有可能是重疊的日期範圍相同的設備!

例如,下面給出的數據:

EquipmentID|ProblemID|BreakdownDate|IssueFixedDate 
1   |1  |01-Jun-2011 |01-Sep-2011 
1   |2  |01-Jun-2011 |01-Oct-2011 
2   |1  |01-Jun-2011 |01-Oct-2011 
2   |2  |01-Jun-2011 |01-Oct-2011 
3   |1  |15-Jun-2011 |01-Sep-2011 
3   |2  |10-Jun-2011 |25-Aug-2011 
4   |1  |01-Jun-2011 |01-Aug-2011 
4   |2  |10-Sep-2011 |22-Oct-2011 
5   |1  |01-Jun-2011 |15-Jun-2011 
5   |2  |02-Jun-2011 |NULL 

現在我想查詢它可以計算每個天是設備倒閉的數量。如果IssueFixedDate爲NULL,那麼我們假定設備仍然不存在,因此計算直到當前日期的Defunct天數。

預期的結果集應該是:

EquipmentID|DefunctDays 
1   |122 
2   |122 
3   |83 
4   |103 
5   |143 

我使用SQL Server 2008中因此,即使熱膨脹係數,光標等都是可以接受的。

感謝
Raghu

回答

3

這使用master..spt_values作爲adhoc輔助數字表。您可以使用one of the techniques here(開始編號爲零)創建您自己的專用號碼錶。

;WITH Numbers 
    AS (SELECT number 
     FROM master..spt_values 
     WHERE type = 'P') 
SELECT EquipmentID, 
     COUNT(DISTINCT number + DATEDIFF(DAY,0, BreakdownDate)) - 1 AS DefunctDays 
FROM BreakdownLog 
     JOIN Numbers N 
     ON number <= DATEDIFF(DAY, BreakdownDate, 
         ISNULL(IssueFixedDate, GETDATE())) 
GROUP BY EquipmentID 
+0

+1 ....但aaaaah ...花了15分鐘才能理解它,我不確定我能否以相同的方式重寫它。 – xanatos

+0

我不會使用spt_values表,因爲它沒有證件性質。但是,與xanatos給出的CTE相比,確實是一個非常簡單的查詢。 – Raghu

+0

我會給你另外一個鏈接的+1,因爲它非常有趣:-) – xanatos

2

它應該是這樣的:

測試表初始化

DROP TABLE BreakdownLog 

CREATE TABLE BreakdownLog 
(
    EquipmentID INT, 
    ProblemID INT, 
    BreakdownDate DATETIME, 
    IssueFixedDate DATETIME NULL 
); 

INSERT INTO BreakDownLog VALUES (1, 1, '01-Jun-2011', '01-Sep-2011') 
INSERT INTO BreakDownLog VALUES (1, 2, '01-Jun-2011', '01-Oct-2011') 
INSERT INTO BreakDownLog VALUES (2, 1, '01-Jun-2011', '01-Oct-2011') 
INSERT INTO BreakDownLog VALUES (2, 2, '01-Jun-2011', '01-Oct-2011') 
INSERT INTO BreakDownLog VALUES (3, 1, '15-Jun-2011', '01-Sep-2011') 
INSERT INTO BreakDownLog VALUES (3, 2, '10-Jun-2011', '25-Aug-2011') 
INSERT INTO BreakDownLog VALUES (4, 1, '01-Jun-2011', '01-Aug-2011') 
INSERT INTO BreakDownLog VALUES (4, 2, '10-Sep-2011', '22-Oct-2011') 
INSERT INTO BreakDownLog VALUES (5, 1, '01-Jun-2011', '15-Jun-2011') 
INSERT INTO BreakDownLog VALUES (5, 2, '02-Jun-2011', NULL) 

真正的代碼

-- We exchange the NULLs in IssueFixedDate with the current date 
; WITH Base AS (
    SELECT EquipmentID, ProblemID, BreakdownDate 
     , ISNULL(IssueFixedDate 
      , CONVERT(VARCHAR(10), GETDATE(), 101)) IssueFixedDate 
    -- The previous line generates the current date without time 
    FROM BreakDownLog 
) 

-- We generate a table with all the days the equipment was broken. 
-- This is done through a recursive CTE 
, BaseDays AS (
    SELECT EquipmentID, BreakdownDate AS DefunctDay, IssueFixedDate FROM Base 
    UNION ALL 
    SELECT EquipmentID, DefunctDay + 1 AS DefunctDay, IssueFixedDate 
     FROM BaseDays 
     WHERE DefunctDay + 1 <= IssueFixedDate 
    -- In T-SQL if you add 1 to a DateTime it's equivalent to adding a day 
) 

-- We make a distinct on the days where the equipment was broken, 
-- to delete days where the equipment was broken for two reasons 
, BaseDaysDistinct AS (
    SELECT DISTINCT EquipmentID, DefunctDay 
     FROM BaseDays 
) 

-- We group the equipment's DefunctDays by EquipmentID 
SELECT EquipmentID, COUNT(*) DefunctDays 
    FROM BaseDaysDistinct 
    GROUP BY EquipmentID 

我們可以在已經改變了過去兩個選擇:

SELECT EquipmentID, COUNT(DISTINCT DefunctDay) DefunctDays 
    FROM BaseDays 
    GROUP BY EquipmentID 

簡化我生成使用遞歸CTE BreakdownDate和IssueFixedDate之間的天列表,刪除多次出現並數着日子更天。

+0

此功能現在可用。不過,我已經在桌面上有大約10K條記錄,並且需要8秒以上才能完成! BreakdownLog表將繼續增長。現在,狩獵正在尋找一種技術來加快查詢速度。 有任何建議,以使其受歡迎。 謝謝, Raghu – Raghu

+1

@Raghu如果修復時間始終<1027,您可以使用Martin Smith的解決方案,否則您可以預先生成一個數字表,如Martin Smith的鏈接 – xanatos

+0

中所建議的那樣。 1027天是很多時間來修復一個設備!所以,我要用Martin Smith的解決方案;只有我將自己創建Numbers表而不是使用spt_values表。無論如何,感謝基於CTE的解決方案。 – Raghu