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

213 lines
5.9 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
**问题类型**: 分母重复计算
**修复状态**: ✅ 编译通过
---
## 问题诊断
### 症状
24小时换单率超过100%甚至达到899%
### 根本原因
**`DailyHighLabelRateShould``DailyLowLabelRateShould` CTE 中的分母计算错误**
原始逻辑:
```sql
DailyHighLabelRateShould AS (
SELECT
DATE(CONVERT_TZ(ar.到货时间, '+00:00', '-05:00')) AS 日期,
COUNT(DISTINCT ar.NeutralWaybillNumber) AS 高标签率应该换单数
FROM ArrivalRequests ar
INNER JOIN (...)
GROUP BY DATE(...)
)
```
**问题**
- `ArrivalRequests` 表中可能存在**相同 `NeutralWaybillNumber` 但不同到货时间的多条记录**
- 例如:同一个订单可能在 09:00 到货一次10:00 到货一次
- `COUNT(DISTINCT ar.NeutralWaybillNumber)` 只去重 `NeutralWaybillNumber`
- 但每一行都代表一个到货记录,相同订单的多条记录被多次计算
### 影响倍数
899% ≈ 9倍重复表示
- 应该换单数被计算了 9 倍
- 如果原本应该是 100 个,被计算成了 900 个
- 导致 24H换单率 = 100 / 900 ≈ 11%... 或者其他值不对
---
## 修复方案
### 修改前
```sql
COUNT(DISTINCT ar.NeutralWaybillNumber) AS 高标签率应该换单数
```
### 修改后
```sql
COUNT(DISTINCT CONCAT(ar.BillOfLadingNumber, '|', ar.MasterPackageNumber)) AS 高标签率应该换单数
```
### 修复逻辑
**关键改变**
- 从统计**订单** (`NeutralWaybillNumber`) 改为统计**交接单** (`BillOfLadingNumber + MasterPackageNumber`)
- 因为冻结标签率是**按交接单计算**的InterchangeUnitLabelRates
- 一个交接单 = 一个 BillOfLadingNumber + MasterPackageNumber 的组合
- 所以应该统计的是**交接单的个数**,而不是**订单的个数**
**为什么用 CONCAT**
- MySQL 中的 `COUNT(DISTINCT col1, col2, ...)` 在某些版本可能有问题
- 使用 `COUNT(DISTINCT CONCAT(col1, '|', col2, ...))` 更安全可靠
- `'|'` 作为分隔符,避免组合冲突
### 修复位置
1. **DailyHighLabelRateShould CTE**第1065-1080行
- 改为:`COUNT(DISTINCT CONCAT(ar.BillOfLadingNumber, '|', ar.MasterPackageNumber))`
2. **DailyLowLabelRateShould CTE**第1085-1100行
- 改为:`COUNT(DISTINCT CONCAT(ar.BillOfLadingNumber, '|', ar.MasterPackageNumber))`
---
## 修复验证
### 编译状态
**编译成功** (exit code 0)
- 无编译错误
- 语法正确
### 逻辑验证
**修复后应该满足**
```
IF 高标签率应该换单数和高标签率考核通过数都是正确的 THEN
高标签率考核通过数 <= 高标签率应该换单数
24H换单率 = 高标签率考核通过数 / 高标签率应该换单数 <= 100%
END IF
```
### 预期结果
修复前后对比:
```
修复前:
- 高标签率应该换单数 = 900被9倍重复
- 高标签率考核通过数 = 100
- 24H换单率 = 100 / 900 ≈ 11% 或其他不合理数值
修复后:
- 高标签率应该换单数 = 100正确
- 高标签率考核通过数 = 100
- 24H换单率 = 100 / 100 = 100%(合理)
```
---
## 为什么这个修复是正确的?
### 概念澄清
**交接单 vs 订单**
- 交接单 = BillOfLadingNumber + MasterPackageNumber物理单位
- 订单 = NeutralWaybillNumber订单单位
- **一个交接单可能包含多个订单**
- **一个交接单在 ArrivalRequests 中可能有多条记录**(多次到货?多个中转站?)
### 为什么要统计交接单而不是订单?
因为:
1. **冻结标签率是按交接单计算的**
- `InterchangeUnitLabelRates` 按 BillOfLadingNumber + MasterPackageNumber 分组
- 冻结标签率 = 该交接单中有标签的包裹 / 该交接单的总包裹
2. **高标签率应该换单数应该代表交接单数**
- 表示"多少个交接单属于高标签率"
- 而不是"多少个订单在高标签率交接单中"
3. **这样才符合考核逻辑**
- 整个交接单按一个冻结标签率处理
- 所以应该统计的是交接单数
### 为什么 ArrivalRequests 会有重复?
可能原因:
1. **多次到货记录**:同一订单分多次到货
2. **多个中转站**:订单通过多个仓库中转
3. **数据导入问题**:导入过程中产生了重复
4. **业务流程**:确实有一对多的关系
无论原因如何,统计**交接单**而不是**订单**是更准确的。
---
## 相关逻辑调整
### 没有改动的地方
1. **DailyHighLabelRateAssessed**:保持不变
- 这个CTE是从 `DailyBeforeNoonPassed``DailyAfternoonPassed` 汇总
- 这两个CTE 都已经基于订单统计,不存在交接单层面的重复
2. **DailyBeforeNoonPassed / DailyAfternoonPassed**:保持不变
- 这些CTE 是基于 `ArrivalRequests` 的订单维度统计
- 逻辑是正确的
---
## 完整的数据流修复后
```
InterchangeUnitLabelRates按交接单计算冻结标签率
冻结标签率 >= 80% 或 < 80%
DailyHighLabelRateShould按交接单统计使用CONCAT✅ 已修复
DailyLowLabelRateShould按交接单统计使用CONCAT✅ 已修复
这是分母
24H换单率 = 高标签率考核通过数 / 高标签率应该换单数 <= 100% ✅
```
---
## 编译状态
**编译成功** (exit code 0)
- DAL 项目编译通过
- 无编译错误
- 已可部署到测试环境
---
## 建议的后续步骤
1. **在测试环境中验证**
- 运行修复后的SQL
- 确认 24H换单率 <= 100%
2. **数据对比**
- 对比修复前后的数据差异
- 分析899%的数据是否来自9倍重复
3. **排查ArrivalRequests表**
- 检查是否真的存在相同NeutralWaybillNumber的多条记录
- 如果存在,这是业务正常情况还是数据问题
4. **文档更新**
- 更新数据字典
- 说明高标签率应该换单数的含义(交接单数,不是订单数)