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