# SQL逻辑错误修复方案

## 问题诊断

**用户发现的逻辑问题**：
```
当日换单成功数 < 16点前考核通过数 + 16点后考核通过数
```

这违反了基本的数学关系：**考核通过的包裹数 ≤ 成功的包裹数**

---

## 根本原因

### 当前SQL的日期维度混乱

| CTE | 日期维度 | 计算逻辑 | 问题 |
|-----|---------|---------|------|
| **DailySuccessCount** | 扫描日期 | 按扫描成功时的日期 | ❌ 不同维度 |
| **DailyBeforeNoonPassed** | 到货日期 | 按订单到货时的日期 | ❌ 不同维度 |
| **DailyAfternoonPassed** | 到货日期 | 按订单到货时的日期 | ❌ 不同维度 |

### 导致的结果

```
示例：
订单A: 到货日期=05-15, 首次成功日期=05-16, 到货时间=15:30(16点前)

当前统计：
- 05-15 的"16点前考核通过数"包含订单A ❌（错误！订单A 05-15还未成功）
- 05-16 的"当日换单成功数"包含订单A ✓
- 结果：05-15 的考核通过数可能 > 成功数（矛盾！）
```

---

## 正确的逻辑

### 所有指标都应该按"首次成功日期"分组

```sql
当日换单成功数 = COUNT(DISTINCT 首次成功日期=当天的包裹)

16点前考核通过 = COUNT(DISTINCT 
    首次成功日期=当天 
    AND 满足考核时间 
    AND 到货时间<16点 的包裹)

16点后考核通过 = COUNT(DISTINCT
    首次成功日期=当天 
    AND 满足考核时间 
    AND 到货时间≥16点 的包裹)
```

### 数学关系

```
当日换单成功数 = 16点前成功数 + 16点后成功数
当日考核通过数 = 16点前考核通过 + 16点后考核通过
考核通过数 ≤ 成功数 ✓
```

---

## 修复步骤

### 步骤1：修改DailySuccessCount

**当前（错误）**：
```sql
DailySuccessCount AS (
    SELECT 
        DATE(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00')) AS 日期,  ← 扫描日期
        ...
```

**改为（正确）**：
```sql
DailySuccessCount AS (
    SELECT 
        DATE(CONVERT_TZ(oss.首次成功时间, '+00:00', '-05:00')) AS 日期,  ← 首次成功日期
        COUNT(DISTINCT oss.NeutralWaybillNumber) AS 当日换单成功数
    FROM OverallScanStatus oss
    INNER JOIN ArrivalRequests ar ON oss.NeutralWaybillNumber = ar.NeutralWaybillNumber
    WHERE oss.曾成功 = 1 AND oss.首次成功时间 IS NOT NULL
    GROUP BY DATE(CONVERT_TZ(oss.首次成功时间, '+00:00', '-05:00'))
)
```

### 步骤2：修改DailyBeforeNoonPassed

**当前（错误）**：
```sql
DailyBeforeNoonPassed AS (
    SELECT 
        ar.到货日期 AS 日期,  ← 到货日期（错！）
        COUNT(DISTINCT ar.NeutralWaybillNumber) AS 16点前考核通过包裹数
    FROM ArrivalRequests ar
    ...
    GROUP BY ar.到货日期
)
```

**改为（正确）**：
```sql
DailyBeforeNoonPassed AS (
    SELECT 
        DATE(CONVERT_TZ(oss.首次成功时间, '+00:00', '-05:00')) AS 日期,  ← 首次成功日期
        COUNT(DISTINCT ar.NeutralWaybillNumber) AS 16点前考核通过包裹数
    FROM ArrivalRequests ar
    INNER JOIN OverallScanStatus oss ON ar.NeutralWaybillNumber = oss.NeutralWaybillNumber
    WHERE 
        oss.曾成功 = 1 
        AND oss.首次成功时间 IS NOT NULL
        -- 16点前到仓
        AND HOUR(ar.到货时间) < 16
        -- 满足考核时间
        AND (
            (ar.考核时间 IS NOT NULL AND CONVERT_TZ(oss.首次成功时间, '+00:00', '-05:00') <= ar.考核时间)
            OR (ar.考核时间 IS NULL)
        )
    GROUP BY DATE(CONVERT_TZ(oss.首次成功时间, '+00:00', '-05:00'))
)
```

### 步骤3：修改DailyAfternoonPassed

**当前（错误）**：
```sql
DailyAfternoonPassed AS (
    SELECT 
        ar.到货日期 AS 日期,  ← 到货日期（错！）
        COUNT(DISTINCT ar.NeutralWaybillNumber) AS 16点后考核通过包裹数
    FROM ArrivalRequests ar
    ...
    GROUP BY ar.到货日期
)
```

**改为（正确）**：
```sql
DailyAfternoonPassed AS (
    SELECT 
        DATE(CONVERT_TZ(oss.首次成功时间, '+00:00', '-05:00')) AS 日期,  ← 首次成功日期
        COUNT(DISTINCT ar.NeutralWaybillNumber) AS 16点后考核通过包裹数
    FROM ArrivalRequests ar
    INNER JOIN OverallScanStatus oss ON ar.NeutralWaybillNumber = oss.NeutralWaybillNumber
    WHERE 
        oss.曾成功 = 1 
        AND oss.首次成功时间 IS NOT NULL
        -- 16点后到仓
        AND HOUR(ar.到货时间) >= 16
        -- 满足考核时间
        AND (
            (ar.考核时间 IS NOT NULL AND CONVERT_TZ(oss.首次成功时间, '+00:00', '-05:00') <= ar.考核时间)
            OR (ar.考核时间 IS NULL)
        )
    GROUP BY DATE(CONVERT_TZ(oss.首次成功时间, '+00:00', '-05:00'))
)
```

---

## 修改影响分析

### 直接影响的CTE

- ✏️ `DailySuccessCount` - 修改日期维度
- ✏️ `DailyBeforeNoonPassed` - 修改日期维度 + JOIN逻辑
- ✏️ `DailyAfternoonPassed` - 修改日期维度 + JOIN逻辑

### 间接受影响的CTE

- `DailyStatsWithPrev` - 需要验证是否需要调整
- 最终SELECT - 可能需要调整来源

### 可以删除的CTE

- ❌ `Daily24HCompletedOrders` - 现在已被DailySuccessCount覆盖
- ❌ `DailyCompletedOrders` - 现在已被DailySuccessCount覆盖（如果只关心成功包裹）

---

## 验证修改后的逻辑

修改后应该满足：

```
∀日期d:
  当日换单成功数(d) 
    = 16点前首次成功数(d) + 16点后首次成功数(d)
    
  16点前考核通过(d) ≤ 16点前首次成功数(d)
  16点后考核通过(d) ≤ 16点后首次成功数(d)
  
  当日换单成功数(d) ≥ 当日考核通过数(d)
```

---

## 报表对比

### 修改前（错误）
```
日期      当日成功数  16点前考核  16点后考核  检查
05-16     50        60         20        ❌ 60+20 > 50 (矛盾！)
```

### 修改后（正确）
```
日期      当日成功数  16点前成功  16点前考核  16点后成功  16点后考核  检查
05-16     80        50         45        30         20        ✅ 80=50+30, 65≤80
```

---

## 总结

**核心修改原则**：

所有关于"成功"和"考核通过"的统计，都必须基于**首次成功日期**，而不是**到货日期**或**扫描日期**。

这样才能保证：**考核通过数 ≤ 成功数** 的基本逻辑关系。

