状态的平均持续时间 - 差距和岛屿



我正在尝试计算处于维修状态的设备的平均周转时间。

我能够创建一个查询,其中包含设备列表及其每天的快照状态。

+-----------------+--------------+--------+----------------------+------------+------------------+
| equipmentNumber | snapshotDate | status | previousSnapshotDate | prevStatus | statusChangeFlag |
+-----------------+--------------+--------+----------------------+------------+------------------+
|          123456 | 2018-04-29   | ONHIRE | 2018-04-28           | AVAILABLE  |                1 |
|          123456 | 2018-04-30   | ONHIRE | 2018-04-29           | ONHIRE     |                0 |
|          123456 | 2018-05-01   | ONHIRE | 2018-04-30           | ONHIRE     |                0 |
|          123456 | 2018-05-02   | REPAIR | 2018-05-01           | ONHIRE     |                1 |
|          123456 | 2018-05-03   | REPAIR | 2018-05-02           | REPAIR     |                0 |
|          123456 | 2018-05-04   | ONHIRE | 2018-05-03           | REPAIR     |                1 |
|          654321 | 2018-04-30   | REPAIR | 2018-04-29           | AVAILABLE  |                1 |
|          654321 | 2018-05-01   | REPAIR | 2018-04-30           | REPAIR     |                0 |
|          654321 | 2018-05-02   | REPAIR | 2018-05-01           | REPAIR     |                0 |
+-----------------+--------------+--------+----------------------+------------+------------------+

因此,在此示例中,我们有 2 台设备,"123456"在 5 月 2 日和 5 月 3 日处于维修状态 2 天,"654321"在 4 月 30 日、5 月 1 日和 5 月 2 日处于维修状态 3 天。 这将是 (2+3(/2 = 2.5 天的平均维修周转时间。

我尝试了这种算法(使用 SQL 检测连续日期范围(,但它似乎不太适合我的需求。

我尝试使用递增 ID 列回答差距和孤岛,如果不存在,请创建一个,以及ROW_NUMBER窗口函数

CREATE TABLE T1
([equipmentNumber] int, [snapshotDate] datetime, [status] varchar(6), [previousSnapshotDate] datetime, [prevStatus] varchar(9), [statusChangeFlag] int)
;
INSERT INTO T1
([equipmentNumber], [snapshotDate], [status], [previousSnapshotDate], [prevStatus], [statusChangeFlag])
VALUES
(123456, '2018-04-29 00:00:00', 'ONHIRE', '2018-04-28 00:00:00', 'AVAILABLE', 1),
(123456, '2018-04-30 00:00:00', 'ONHIRE', '2018-04-29 00:00:00', 'ONHIRE', 0),
(123456, '2018-05-01 00:00:00', 'ONHIRE', '2018-04-30 00:00:00', 'ONHIRE', 0),
(123456, '2018-05-02 00:00:00', 'REPAIR', '2018-05-01 00:00:00', 'ONHIRE', 1),
(123456, '2018-05-03 00:00:00', 'REPAIR', '2018-05-02 00:00:00', 'REPAIR', 0),
(123456, '2018-05-04 00:00:00', 'ONHIRE', '2018-05-03 00:00:00', 'REPAIR', 1),
(654321, '2018-04-30 00:00:00', 'REPAIR', '2018-04-29 00:00:00', 'AVAILABLE', 1),
(654321, '2018-05-01 00:00:00', 'REPAIR', '2018-04-30 00:00:00', 'REPAIR', 0),
(654321, '2018-05-02 00:00:00', 'REPAIR', '2018-05-01 00:00:00', 'REPAIR', 0)
;
;WITH cteX
AS(
SELECT
Id = ROW_NUMBER()OVER(ORDER BY T.equipmentNumber, T.snapshotDate)
,T.equipmentNumber
,T.snapshotDate
,T.[status]
,T.previousSnapshotDate
,T.prevStatus
,T.statusChangeFlag
FROM dbo.T1 T
),cteIsland
AS(
SELECT 
Island = X.Id - ROW_NUMBER()OVER(ORDER BY X.Id)
,*
FROM cteX X
WHERE X.[status] = 'REPAIR'
)
SELECT * FROM cteIsland

请注意Island

Island  Id  equipmentNumber status
3       4   123456          REPAIR
3       5   123456          REPAIR
4       7   654321          REPAIR
4       8   654321          REPAIR
4       9   654321          REPAIR

使用Island列,您可以通过此TSQL获得所需的答案

;WITH cteX
AS(
SELECT
Id = ROW_NUMBER()OVER(ORDER BY T.equipmentNumber, T.snapshotDate)
,T.equipmentNumber
,T.snapshotDate
,T.[status]
,T.previousSnapshotDate
,T.prevStatus
,T.statusChangeFlag
FROM dbo.T1 T
),cteIsland
AS(
SELECT 
Island = X.Id - ROW_NUMBER()OVER(ORDER BY X.Id)
,*
FROM cteX X
WHERE X.[status] = 'REPAIR'
)
SELECT 
AvgDuration =SUM(Totals.IslandCounts) / (COUNT(Totals.IslandCounts) * 1.0)
FROM
(
SELECT 
IslandCounts = COUNT(I.Island)
,I.equipmentNumber
FROM cteIsland I
GROUP BY I.equipmentNumber
) Totals

AvgDuration
2.50000000000000

这是 SQLFiddle

该方法应该可以识别修复周期:

select equipmentNumber, min(snapshotDate), max(snapshotDate)
from (select t.*,
row_number() over (partition by equipmentNumber order by snapshotDate) as seqnum
from t
) t
where status = 'REPAIR'
group by equipmentNumber, dateadd(day, - seqnum, snapshotDate);

您可以使用子查询获取平均值:

select avg(datediff(day, minsd, maxsd) * 1.0)
from (select equipmentNumber, min(snapshotDate) as minsd, max(snapshotDate) as maxsd
from (select t.*,
row_number() over (partition by equipmentNumber order by snapshotDate) as seqnum
from t
) t
where status = 'REPAIR'
group by equipmentNumber, dateadd(day, - seqnum, snapshotDate)
) e;

最新更新