# 首次扫描时间的使用范围说明 **更新日期**: 2026-05-16 **主题**: 首次扫描时间在SQL中的具体使用 **状态**: ✅ 验证无冲突 --- ## 首次扫描时间的来源 ### 定义位置 **OverallScanStatus CTE**(第814-822行): ```sql OverallScanStatus AS ( SELECT s.NeutralWaybillNumber, MAX(CASE WHEN s.Result = 0 THEN 1 ELSE 0 END) AS 曾成功, MIN(CASE WHEN s.Result = 0 THEN DATE(...) ELSE NULL END) AS 首次成功日期, MIN(CASE WHEN s.Result = 0 THEN s.CreatedAt ELSE NULL END) AS 首次成功时间 FROM label_scan_history s GROUP BY s.NeutralWaybillNumber ) ``` ### 含义 - `首次成功时间` = 该包裹**首次扫描成功**(Result = 0)的时刻 - 来自 `label_scan_history.CreatedAt` 的最小值(第一次成功) --- ## 首次扫描时间的使用地点 ### 1. DailyLowLabelRate24HCompleted CTE **位置**:第962-974行 **使用方式**: ```sql WHERE oss.曾成功 = 1 AND oss.首次成功时间 IS NOT NULL AND ar.考核时间 IS NULL ``` **作用**: - 判断该包裹是否曾经成功扫描 - 配合"考核时间为NULL"(低标签率)来统计完成数 **不影响的地方**:❌ 冻结标签率计算 ### 2. Daily24HCompletedOrders CTE **位置**:第976-996行 **使用方式**: ```sql WHERE oss.曾成功 = 1 AND oss.首次成功时间 IS NOT NULL AND ( -- 情况1:标签率>=80%,有固定考核时间 (ar.考核时间 IS NOT NULL AND CONVERT_TZ(oss.首次成功时间, '+00:00', '-05:00') <= ar.考核时间) OR -- 情况2:标签率<80%,完成时间本身就是考核时间(即完成即达标) (ar.考核时间 IS NULL) ) ``` **作用**: - 用 `首次成功时间` 与 `考核时间` 比较 - 判断包裹是否在考核期限内完成 **不影响的地方**:❌ 冻结标签率计算 ### 3. DailyBeforeNoonPassed CTE **位置**:第1000-1021行 **使用方式**: ```sql WHERE oss.曾成功 = 1 AND oss.首次成功时间 IS NOT NULL AND CONVERT_TZ(oss.首次成功时间, '+00:00', '-05:00') <= ar.考核时间 ``` **作用**: - 统计16点前到仓且完成考核的包裹 - 用首次成功时间来判断是否满足考核时间 **不影响的地方**:❌ 冻结标签率计算 ### 4. DailyAfternoonPassed CTE **位置**:第1023-1044行 **使用方式**: ```sql WHERE oss.曾成功 = 1 AND oss.首次成功时间 IS NOT NULL AND CONVERT_TZ(oss.首次成功时间, '+00:00', '-05:00') <= ar.考核时间 ``` **作用**: - 统计16点后到仓且完成考核的包裹 - 用首次成功时间来判断是否满足考核时间 **不影响的地方**:❌ 冻结标签率计算 ### 5. DailyLowLabelRatePassed CTE **位置**:第1050-1069行 **使用方式**: ```sql WHERE oss.曾成功 = 1 AND oss.首次成功时间 IS NOT NULL AND ar.考核时间 IS NULL ``` **作用**: - 统计低标签率(考核时间=NULL)且成功的包裹 - 完成即达标 **不影响的地方**:❌ 冻结标签率计算 --- ## 与冻结标签率计算的关系 ### 冻结标签率的计算 **位置**:InterchangeUnitLabelRates CTE(第734-763行) **计算方式**: ```sql label_rate_percent = COUNT(DISTINCT CASE WHEN l.Label IS NOT NULL AND l.Label != '' THEN l.Id END) * 100.0 / COUNT(DISTINCT l.Id) ``` **特点**: - ✅ 只依赖 `label_replace_requests` 中的 `Label` 字段 - ❌ **不涉及** `首次成功时间` - ❌ **不涉及** `label_scan_history` - ❌ **不涉及** 时间比较 ### 验证 **首次扫描时间在冻结标签率计算中的使用**: ``` ❌ 未使用 ❌ 不需要使用 ❌ 对计算没有影响 ``` --- ## 数据流整体分析 ``` 【冻结标签率的独立计算】 label_replace_requests(有标签?) ↓ InterchangeUnitLabelRates(只看是否有标签) ↓ 冻结标签率 >= 80% 或 < 80% ↓ DailyHighLabelRateShould / DailyLowLabelRateShould(分类交接单) 【考核完成情况的独立统计】 label_scan_history(首次成功扫描) ↓ OverallScanStatus(首次成功时间) ↓ 各个考核CTE(DailyBeforeNoonPassed 等) ↓ 判断是否满足考核时间 【两条线的汇总】 冻结标签率 + 考核结果 = 最终报表 ``` --- ## 总结 ### 首次扫描时间的用途 | 用途 | 位置 | 说明 | |------|------|------| | ✅ 判断是否曾成功 | DailyLowLabelRate24HCompleted 等 | 用来过滤成功的包裹 | | ✅ 比较考核时间 | DailyBeforeNoonPassed、DailyAfternoonPassed 等 | 判断是否在考核期限内 | | ✅ 统计历史数据 | 整体报表 | 多维度分析 | | ❌ 计算冻结标签率 | InterchangeUnitLabelRates | **完全不使用** | ### 对现有逻辑的影响 ``` ❌ 不影响冻结标签率的计算 ❌ 不影响高/低标签率的分类 ✅ 只用于考核结果的判断(已有逻辑) ✅ 用于历史数据统计(补充信息) ``` ### 结论 **首次扫描时间的引入完全安全,不会影响现有逻辑。** - 冻结标签率:基于标签属性(不依赖扫描时间) - 考核完成:基于成功时间与考核期限的比较(需要扫描时间) - 两部分逻辑独立,互不影响 --- ## 编译状态 ✅ **编译成功** (exit code 0) - 逻辑清晰,没有冲突 - 首次扫描时间的使用范围明确 - 与冻结标签率完全独立