基于停机事件表计算月度内至少一厂运行的总时长
解决工厂运行时长计算的问题
咱们一步步拆解你的问题,把计算逻辑修正过来,得到正确的685.85小时结果。
问题回顾
你有记录Plant14和Plant15停机事件的数据集,需要计算2017年12月内至少一座工厂未停机的总时长。已知Plant14整月停机,Plant15总停机时长为58.15小时,正确结果应为31×24 - 58.15 = 685.85小时,但现有查询只返回了528小时,说明计算逻辑存在问题。
先把你的停机数据整理成清晰的表格:
| EventID | DayCode | Plant | START | FINISH |
|---|---|---|---|---|
| 76093 | 4516 | 14 | 2017-12-01 06:00:00.000 | 2017-12-02 06:00:00.000 |
| 76098 | 4516 | 15 | 2017-12-01 15:30:00.000 | 2017-12-02 06:00:00.000 |
| 76099 | 4517 | 14 | 2017-12-02 06:00:00.000 | 2017-12-03 06:00:00.000 |
| 76101 | 4517 | 15 | 2017-12-02 06:00:00.000 | 2017-12-03 06:00:00.000 |
| 76106 | 4518 | 14 | 2017-12-03 06:00:00.000 | 2017-12-04 06:00:00.000 |
| 76127 | 4518 | 15 | 2017-12-03 06:00:00.000 | 2017-12-03 17:40:00.000 |
| 76112 | 4519 | 14 | 2017-12-04 06:00:00.000 | 2017-12-05 06:00:00.000 |
| 76117 | 4520 | 14 | 2017-12-05 06:00:00.000 | 2017-12-06 06:00:00.000 |
| 76122 | 4521 | 14 | 2017-12-06 06:00:00.000 | 2017-12-07 06:00:00.000 |
| 76128 | 4522 | 14 | 2017-12-07 06:00:00.000 | 2017-12-08 06:00:00.000 |
| 76133 | 4523 | 14 | 2017-12-08 06:00:00.000 | 2017-12-09 06:00:00.000 |
| 76138 | 4524 | 14 | 2017-12-09 06:00:00.000 | 2017-12-10 06:00:00.000 |
| 76151 | 4525 | 14 | 2017-12-10 06:00:00.000 | 2017-12-11 06:00:00.000 |
| 76155 | 4526 | 14 | 2017-12-11 06:00:00.000 | 2017-12-12 06:00:00.000 |
| 76159 | 4527 | 14 | 2017-12-12 06:00:00.000 | 2017-12-13 06:00:00.000 |
| 76163 | 4528 | 14 | 2017-12-13 06:00:00.000 | 2017-12-14 06:00:00.000 |
| 76168 | 4529 | 14 | 2017-12-14 06:00:00.000 | 2017-12-15 06:00:00.000 |
| 76172 | 4530 | 14 | 2017-12-15 06:00:00.000 | 2017-12-16 06:00:00.000 |
| 76176 | 4531 | 14 | 2017-12-16 06:00:00.000 | 2017-12-17 06:00:00.000 |
| 76180 | 4532 | 14 | 2017-12-17 06:00:00.000 | 2017-12-18 06:00:00.000 |
| 76184 | 4533 | 14 | 2017-12-18 06:00:00.000 | 2017-12-19 06:00:00.000 |
| 76188 | 4534 | 14 | 2017-12-19 06:00:00.000 | 2017-12-20 06:00:00.000 |
| 76192 | 4535 | 14 | 2017-12-20 06:00:00.000 | 2017-12-21 06:00:00.000 |
| 76196 | 4536 | 14 | 2017-12-21 06:00:00.000 | 2017-12-22 06:00:00.000 |
| 76199 | 4537 | 14 | 2017-12-22 06:00:00.000 | 2017-12-23 06:00:00.000 |
| 76202 | 4538 | 14 | 2017-12-23 06:00:00.000 | 2017-12-24 06:00:00.000 |
| 76205 | 4539 | 14 | 2017-12-24 06:00:00.000 | 2017-12-25 06:00:00.000 |
| 76207 | 4540 | 14 | 2017-12-25 06:00:00.000 | 2017-12-26 06:00:00.000 |
| 76209 | 4541 | 14 | 2017-12-26 06:00:00.000 | 2017-12-27 06:00:00.000 |
| 76211 | 4542 | 14 | 2017-12-27 06:00:00.000 | 2017-12-28 06:00:00.000 |
| 76213 | 4543 | 14 | 2017-12-28 06:00:00.000 | 2017-12-29 06:00:00.000 |
| 76215 | 4544 | 14 | 2017-12-29 06:00:00.000 | 2017-12-30 06:00:00.000 |
| 76217 | 4545 | 14 | 2017-12-30 06:00:00.000 | 2017-12-31 01:00:00.000 |
| 76221 | 4545 | 15 | 2017-12-30 11:58:00.000 | 2017-12-30 12:57:00.000 |
| 76218 | 4545 | 14 | 2017-12-31 01:00:00.000 | 2017-12-31 06:00:00.000 |
| 76223 | 4545 | 15 | 2017-12-31 01:30:00.000 | 2017-12-31 06:00:00.000 |
| 76225 | 4546 | 14 | 2017-12-31 06:00:00.000 | 2017-12-31 08:30:00.000 |
| 76230 | 4546 | 15 | 2017-12-31 06:00:00.000 | 2017-12-31 08:30:00.000 |
| 76229 | 4546 | 14 | 2017-12-31 08:30:00.000 | 2018-01-01 06:00:00.000 |
核心逻辑梳理
首先明确:
至少一座工厂未停机的时长 = 月度总时长 - 两座工厂同时停机的时长
因为Plant14整月处于停机状态,所以两座同时停机的时长 = Plant15的总停机时长(只要Plant15停机,就是双停状态)。所以问题的关键是准确计算Plant15在12月内的总停机时长(合并重叠的停机时间段)。
错误原因分析
你的现有查询得到528小时,大概率是以下问题导致:
- 没有合并Plant15的重叠/连续停机事件,重复计算了时长
- 错误处理了跨天的停机事件,或者错误排除/纳入了12月外的时间段(比如Plant14最后一条跨到2018年的停机,不该计入12月的双停时长)
- 错误计算了Plant14的停机范围,导致双停时长统计错误
正确的SQL解决方案
步骤1:准确计算Plant15的总停机时长
先合并Plant15的重叠停机时间段,再计算总时长:
WITH plant15_shutdown_groups AS ( -- 标记重叠时间段的分组 SELECT START, FINISH, SUM(CASE WHEN prev_finish >= START THEN 0 ELSE 1 END) OVER (ORDER BY START) AS group_id FROM ( -- 获取每个停机事件的前一个事件结束时间 SELECT START, FINISH, LAG(FINISH) OVER (ORDER BY START) AS prev_finish FROM your_table_name WHERE Plant = 15 -- 只统计2017年12月内的停机部分 AND START < '2018-01-01 00:00:00' AND FINISH > '2017-12-01 00:00:00' ) t1 ), merged_shutdowns AS ( -- 合并每个分组的时间段 SELECT group_id, -- 取分组内最早的开始时间,最晚的结束时间,且限制在12月范围内 GREATEST(MIN(START), '2017-12-01 00:00:00') AS merged_start, LEAST(MAX(FINISH), '2017-12-31 23:59:59') AS merged_finish FROM plant15_shutdown_groups GROUP BY group_id ) -- 计算总停机时长(转换为小时) SELECT SUM(DATEDIFF(MINUTE, merged_start, merged_finish)) / 60.0 AS total_plant15_shutdown_hours FROM merged_shutdowns;
这个查询会返回约58.15小时的正确结果。
步骤2:计算目标结果
直接用月度总时长减去Plant15的总停机时长:
WITH plant15_shutdown_groups AS ( SELECT START, FINISH, SUM(CASE WHEN prev_finish >= START THEN 0 ELSE 1 END) OVER (ORDER BY START) AS group_id FROM ( SELECT START, FINISH, LAG(FINISH) OVER (ORDER BY START) AS prev_finish FROM your_table_name WHERE Plant = 15 AND START < '2018-01-01 00:00:00' AND FINISH > '2017-12-01 00:00:00' ) t1 ), merged_shutdowns AS ( SELECT group_id, GREATEST(MIN(START), '2017-12-01 00:00:00') AS merged_start, LEAST(MAX(FINISH), '2017-12-31 23:59:59') AS merged_finish FROM plant15_shutdown_groups GROUP BY group_id ) SELECT 31*24 - SUM(DATEDIFF(MINUTE, merged_start, merged_finish)) / 60.0 AS at_least_one_running_hours FROM merged_shutdowns;
运行这个查询会得到744 - 58.15 = 685.85小时的正确结果。
手动验证Plant15的停机时长
我们可以手动计算Plant15的停机事件,确认总时长:
- 76098:14.5小时(15:30到次日06:00)
- 76101:24小时(06:0
相关产品推荐
相关产品推荐

