Files
LabelChange-server/.trae/documents/24h_rate_final_fix_plan.md
2026-06-01 16:30:29 +08:00

252 lines
7.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 24H换单率超过100% - 最终根本原因与修复计划
**日期**2026-05-16
**核心问题**24H换单率远超100%4745%等),根本原因是分母计算错误
---
## 业务逻辑最终澄清(用户确认)
### 包裹的属性关系
```
考核时间
决定者:作业时的标签率(交接单维度)
标签率(两种)
1. 作业时标签率(固定)
= 最早扫描时间之前的有标签包裹 / 该交接单所有包裹
用途决定考核时间、决定是否纳入24H换单率
2. 统计的标签率(最终)
= 当前有标签的包裹 / 该交接单所有包裹
用途:业务报表展示
```
### 标签率与考核时间的关系
```
对于交接单中的每个包裹:
- 作业时标签率≥80% → 有考核时间 → 需要在规定时间内完成
- 作业时标签率<80% → 无考核时间 → 完成即达标
关键:考核时间是交接单维度确定的,然后应用到该交接单的所有包裹
```
### 分母的精确定义(用户最终确认)
```
高标签率应该换单数 = 当日到货 且 作业时标签率≥80% 的交接单中的有标签包裹数
具体计算方式:
1. 找出当日到货的所有交接单
2. 对每个交接单:
a. 计算作业时标签率 = 最早扫描之前有标签的数 / 总数
b. 如果作业时标签率≥80%
→ 计算这个交接单有多少个有标签的包裹
→ 这些有标签包裹加入应该换单数
c. 如果作业时标签率<80%
→ 跳过这个交接单(不加入应该换单数)
3. 求和得到总的高标签率应该换单数
```
---
## 当前代码的根本问题
### 问题1InterchangeUnitLabelRatesAtFirstScan的计算
**当前代码**第761-791行
```sql
SELECT
l.BillOfLadingNumber,
l.MasterPackageNumber,
COUNT(DISTINCT l.Id) AS total_requests,
COUNT(DISTINCT CASE
WHEN l.Label IS NOT NULL AND l.Label != ''
AND l.LabelRetrievedAt < (...)
THEN l.Id
END) AS labeled_at_first_scan,
...
FROM label_replace_requests l
GROUP BY l.BillOfLadingNumber, l.MasterPackageNumber
```
**问题**
- COUNT(DISTINCT l.Id) 统计的是"所有包裹"的数量
- 但根据用户规则,应该统计的是"有标签的包裹"的数量
**正确做法**
- 分子应该是:最早扫描时间之前有标签的包裹数
- 分母应该是:该交接单所有有标签的包裹数(不是所有包裹)
### 问题2DailyHighLabelRateShould的计算
**当前代码**第1100-1117行
```sql
DailyHighLabelRateShould AS (
SELECT
DATE(CONVERT_TZ(ar.到货时间, '+00:00', '-05:00')) AS 日期,
COUNT(DISTINCT CONCAT(ar.BillOfLadingNumber, '|', ar.MasterPackageNumber))
AS 高标签率应该换单数
FROM ArrivalRequests ar
INNER JOIN InterchangeUnitLabelRatesAtFirstScan...
WHERE label_rate_at_first_scan >= 80
```
**问题**
- 这里统计的是交接单级别的计数
- 但应该统计的是"有标签的包裹"数量
- 如果一个交接单有10个包裹其中8个有标签标签率80%
- 应该换单数应该是8不是1
**导致的后果**
- 分母被严重低估每个交接单只算1而不是该交接单的有标签包裹数
- 分子/分母比率就会巨大
---
## 修复方案
### 第1步修正InterchangeUnitLabelRatesAtFirstScan
**改进思路**
- 保留交接单维度的标签率计算(用于决定考核时间)
- 但同时记录"有标签包裹数"用于分母计算
```sql
InterchangeUnitLabelRatesAtFirstScan AS (
SELECT
l.BillOfLadingNumber,
l.MasterPackageNumber,
-- 统计有标签的包裹数(用于后续分母计算)
COUNT(DISTINCT CASE
WHEN l.Label IS NOT NULL AND l.Label != ''
THEN l.Id
END) AS total_labeled_at_any_time,
-- 作业时有标签的包裹数
COUNT(DISTINCT CASE
WHEN l.Label IS NOT NULL AND l.Label != ''
AND l.LabelRetrievedAt < (
SELECT MIN(lsh.CreatedAt)
FROM label_scan_history lsh
WHERE lsh.NeutralWaybillNumber = l.NeutralWaybillNumber
)
THEN l.Id
END) AS labeled_at_first_scan,
-- 作业时标签率 = 作业时有标签数 / 所有有标签数
ROUND(
COUNT(DISTINCT CASE
WHEN l.Label IS NOT NULL AND l.Label != ''
AND l.LabelRetrievedAt < (
SELECT MIN(lsh.CreatedAt)
FROM label_scan_history lsh
WHERE lsh.NeutralWaybillNumber = l.NeutralWaybillNumber
)
THEN l.Id
END) * 100.0 /
COUNT(DISTINCT CASE
WHEN l.Label IS NOT NULL AND l.Label != ''
THEN l.Id
END),
2
) AS label_rate_at_first_scan
FROM label_replace_requests l
GROUP BY l.BillOfLadingNumber, l.MasterPackageNumber
)
```
### 第2步修正DailyHighLabelRateShould
**改进思路**
- 统计的是"有标签的包裹数",而不是交接单数
```sql
DailyHighLabelRateShould AS (
SELECT
DATE(CONVERT_TZ(ar.到货时间, '+00:00', '-05:00')) AS 日期,
-- 改为统计:有标签的包裹数
SUM(CASE
WHEN iulr_first.label_rate_at_first_scan >= 80
THEN iulr_first.total_labeled_at_any_time
ELSE 0
END) AS 高标签率应该换单数
FROM ArrivalRequests ar
INNER JOIN InterchangeUnitLabelRatesAtFirstScan iulr_first
ON ar.BillOfLadingNumber = iulr_first.BillOfLadingNumber
AND ar.MasterPackageNumber = iulr_first.MasterPackageNumber
WHERE ar.到货日期 IS NOT NULL
GROUP BY DATE(CONVERT_TZ(ar.到货时间, '+00:00', '-05:00'))
)
```
### 第3步确保分子与分母维度一致
**分子的逻辑**DailyBeforeNoonPassed + DailyAfternoonPassed
- 已经是按"订单"NeutralWaybillNumber计数
- 这是正确的
**但需要确保**
- 只统计有标签的订单
- 只统计作业时标签率≥80%的订单
- 只统计在考核时间内完成的订单
---
## 实施步骤
### 步骤1修改InterchangeUnitLabelRatesAtFirstScan CTE
- 位置第761-791行
- 任务添加total_labeled_at_any_time字段调整label_rate_at_first_scan计算逻辑
- 验证:确保新增字段计算正确
### 步骤2修改DailyHighLabelRateShould CTE
- 位置第1100-1117行
- 任务改为SUM统计有标签包裹数而不是COUNT交接单
- 验证:结果应该更大(因为统计包裹而不是交接单)
### 步骤3编译验证
- 运行:`dotnet build src/DAL/DAL.csproj`
- 预期:编译成功
### 步骤4测试和验证
**测试内容**不要求≤100%,因为这是可能的正常现象):
测试1验证分母计算逻辑
```sql
SELECT
日期,
高标签率应该换单数,
(SELECT COUNT(*) FROM ...) as 应该的包裹数
FROM DailyHighLabelRateShould
WHERE 日期 = '2026-05-15'
```
测试2验证分子分母是否合理对应
```sql
SELECT
日期,
(SELECT SUM(...) FROM DailyBeforeNoonPassed WHERE 日期='2026-05-15') as 分子_16点前,
(SELECT SUM(...) FROM DailyAfternoonPassed WHERE 日期='2026-05-15') as 分子_16点后,
(SELECT 高标签率应该换单数 FROM DailyHighLabelRateShould WHERE 日期='2026-05-15') as 分母
```
测试3验证数据是否能手工解释
- 选择某一天的数据
- 查看具体的订单数和包裹数
- 确认分子分母的计算逻辑是否符合业务规则
- **不要求分子≤分母或24H换单率≤100%,因为这是可能的正常现象**
---
## 预期结果
修复后:
- ✅ 分母正确反映"有标签包裹数"而不是"交接单数"
- ✅ 数据逻辑一致、可解释
- ✅ 24H换单率数据合理虽然可能>100%但不会是4745%这样极端的值)
- ✅ 分子分母的对应关系清晰