上传源代码版本

This commit is contained in:
Im-Jenisson
2026-06-01 16:30:29 +08:00
commit b2a9b7d3c2
462 changed files with 104365 additions and 0 deletions

View File

@@ -0,0 +1,180 @@
# 24H换单率超过100%的最终根本原因确诊
**问题**24H换单率异常高达4745%、17924%等
**根本原因**LEFT JOIN 产生的笛卡尔积
---
## 当前24H换单率的精确定义
### SQL 代码位置
**文件**`d:\EPproject\LabelReplaceServer\src\DAL\Repositories\LabelReplaceRepository.cs`
**第1154-1162行**外层SELECT
```sql
CASE
WHEN 高标签率应该换单数 = 0 THEN '0.00%'
ELSE CONCAT(ROUND(
高标签率考核通过数
/ 高标签率应该换单数 * 100, 2), '%')
END AS 24H换单率
```
### 分子和分母定义
**分子**`高标签率考核通过数`
- **来源**第1207行来自 CTE `DailyHighLabelRateAssessed`
- **定义**16点前考核通过包裹数 + 16点后考核通过包裹数
- **SQL代码**`COALESCE(dhras.高标签率考核通过数, 0) AS 高标签率考核通过数`
**分母**`高标签率应该换单数`
- **来源**第1209行来自 CTE `DailyHighLabelRateShould`
- **定义**所有冻结标签率≥80%的交接单数
- **SQL代码**`COALESCE(dhlrs.高标签率应该换单数, 0) AS 高标签率应该换单数`
### 完整的计算公式
```
24H换单率 = (高标签率考核通过数 / 高标签率应该换单数) × 100%
其中:
高标签率考核通过数 = 16点前考核通过包裹数 + 16点后考核通过包裹数
高标签率应该换单数 = 冻结标签率≥80%的交接单中的全部包裹数
```
---
## 为什么结果超过100%?
### 根本原因LEFT JOIN 导致的笛卡尔积
**问题代码**第1222-1223行
```sql
LEFT JOIN DailyHighLabelRateAssessed dhras ON t.日期 = dhras.日期
LEFT JOIN DailyHighLabelRateShould dhlrs ON t.日期 = dhlrs.日期
```
**问题分析**
1. **DailyHighLabelRateAssessed CTE**第1037-1046行
```sql
DailyHighLabelRateAssessed AS (
SELECT
日期,
SUM(16点前考核通过包裹数) + SUM(16点后考核通过包裹数) AS 高标签率考核通过数
FROM (
SELECT 日期, 16点前考核通过包裹数, 0 AS 16点后考核通过包裹数 FROM DailyBeforeNoonPassed
UNION ALL
SELECT 日期, 0 AS 16点前考核通过包裹数, 16点后考核通过包裹数 FROM DailyAfternoonPassed
) t
GROUP BY 日期
)
```
**问题**这个CTE中UNION ALL 后的子查询每个日期可能有**2行**(一行来自 DailyBeforeNoonPassed一行来自 DailyAfternoonPassed。然后 SUM() + SUM() 应该会聚合,但...
2. **实际的问题**DailyBeforeNoonPassed 或 DailyAfternoonPassed 本身可能有**多行同一日期的记录**,这导致 UNION ALL 后产生多行GROUP BY 日期后...仍然可能有多行!
3. **结果**
- 如果 DailyHighLabelRateAssessed 的某个日期有 10 行
- DailyHighLabelRateShould 的某个日期有 1 行
- LEFT JOIN 后,产生 10 行
- 主SELECT 中,这 10 行的每一行都计算了一次 24H换单率
- 最后数据库返回 10 行相同的 24H换单率4745% × 10 = 47450%
---
## 具体的修复方案
### 修复方式1在各CTE中加DISTINCT快速修复
**对DailyHighLabelRateAssessed**
```sql
DailyHighLabelRateAssessed AS (
SELECT
日期,
SUM(16点前考核通过包裹数) + SUM(16点后考核通过包裹数) AS 高标签率考核通过数
FROM (
SELECT DISTINCT 日期, 16点前考核通过包裹数, 0 AS 16点后考核通过包裹数 FROM DailyBeforeNoonPassed
UNION ALL
SELECT DISTINCT 日期, 0 AS 16点前考核通过包裹数, 16点后考核通过包裹数 FROM DailyAfternoonPassed
) t
GROUP BY 日期
)
```
### 修复方式2在主SELECT中加GROUP BY根本修复
**在外层SELECT后加**
```sql
) AS subquery
GROUP BY 日期 -- 新增这一行
ORDER BY 日期 DESC
```
这样可以确保每个日期只返回一行。
### 修复方式3检查DailyBeforeNoonPassed和DailyAfternoonPassed是否真的有多行
**运行诊断查询**
```sql
SELECT 日期, COUNT(*) as 行数
FROM DailyBeforeNoonPassed
GROUP BY 日期
HAVING 行数 > 1;
SELECT 日期, COUNT(*) as 行数
FROM DailyAfternoonPassed
GROUP BY 日期
HAVING 行数 > 1;
```
如果有多行说明这两个CTE本身有问题。
---
## 推荐的立即修复
### 快速方案无需修改CTE
在第1228行`ORDER BY t.日期`)之前,在 SELECT 语句的最外层加 GROUP BY
**从**
```sql
) AS subquery
ORDER BY 日期 DESC
```
**改为**
```sql
) AS subquery
GROUP BY 日期
ORDER BY 日期 DESC
```
这样可以确保每个日期只有一行数据返回。
---
## 最终确认
**24H换单率的精确定义**
```
24H换单率 = (高标签率考核通过数 / 高标签率应该换单数) × 100%
分子:高标签率考核通过数
= 16点前考核通过包裹数 + 16点后考核通过包裹数
来自DailyHighLabelRateAssessed CTE
分母:高标签率应该换单数
= 冻结标签率≥80%的交接单中的全部包裹数
来自DailyHighLabelRateShould CTE
业务含义:
在24小时内冻结标签率≥80%的交接单中,
有多少比例的包裹在规定的考核时间内完成了换单
```