我有一个包含以下列的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 days到当前日期。
预期结果集应为:
EquipmentID|DefunctDays
1 |122
2 |122
3 |83
4 |103
5 |143
我正在使用SQL Server 2008.所以即使是CTE,游标等也是可以接受的。
感谢
Raghu
答案 0 :(得分:3)
这使用master..spt_values
作为特殊辅助数字表。您可以使用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
答案 1 :(得分: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之间的天数列表,删除多次出现的天数并计算天数。