# 两天台账排查逻辑与案例总结

## 1. 这次排查覆盖了哪些对象

这两天实际排查的对象，分成 5 类：

1. 半成品收发存原表  
   `YDM_BC_INITIAL / YDM_BC_INLIST / YDM_BC_OUTLIST`

2. 半成品中间表  
   `CX_YDM_BC_INITIAL / CX_YDM_BC_INLIST / CX_YDM_BC_OUTLIST`

3. 成品收发存原表  
   `YDM_ZC_INITIAL / YDM_ZC_INLIST / YDM_ZC_OUTLIST / YDM_ZC_STOCKTAKINGLIST`

4. 成品中间表  
   `CX_YDM_ZC_INITIAL / CX_YDM_ZC_INLIST / CX_YDM_ZC_OUTLIST`

5. 月报与接口
   - 热轧月报：`HOT_PRODUCTION_MES_RZ`
   - 加工月报：`HOT_PRODUCTION_MES_JG`
   - 判定表：`QCM_ZG_JUGDE_APPLY`
   - 接口日志：`CX_TO_MES_LOG`
   - 提单表：`YDM_ZC_BILL_M / YDM_ZC_BILL_C / YDM_ZC_LOADVEHICLE_MAT`

这 5 类对象里，最容易混淆的是：

- 原表 `YDM_*`：更像“当前业务真实源头”
- 中间表 `CX_*`：更像“给校验/接口/月报使用的结果表”
- `DataValidationResult`：只是某一时点的校验快照，不代表当前库里实时值

所以排查时第一原则是：

**永远先分清“是原表错了，还是 CX 表错了，还是校验结果只是旧快照”。**


## 2. 核对的基本公式

### 2.1 半成品/成品跨月连续性

最常用的判断公式是：

`本月期初 = 上月期初 + 上月入库 - 上月出库 (+ 调差)`

其中：

- 半成品常用：
  - 期初：`YDM_BC_INITIAL`
  - 入库：`YDM_BC_INLIST`
  - 出库：`YDM_BC_OUTLIST`

- 成品常用：
  - 期初：`YDM_ZC_INITIAL`
  - 入库：`YDM_ZC_INLIST`
  - 出库：`YDM_ZC_OUTLIST`
  - 调差：`YDM_ZC_STOCKTAKINGLIST`

### 2.2 月报和台账对比

月报不是直接跟“成品量”比，而是要先明确过程口径。

这次已经确认过一类典型问题：

- 有些第三方是直接拿 `PROD_WEIGHT`
- 但系统过程实际用的是 `PROD_WEIGHT - NVL(LC_WEIGHT, 0)`

所以月报类问题第二原则是：

**先确认“月报值的生成公式”，再谈是不是对不上。**


## 3. 标准排查流程

后面再遇到类似问题，建议固定按下面 8 步走。

### 第 1 步：先确认问题是“哪一层”报出来的

先看报错来自哪里：

- `DataValidationResult`
- 第三方接口校验
- 人工 Excel 对账
- 月报和台账比对

这一步的目的，是避免把“汇总口径问题”误当成“明细错误”。

### 第 2 步：先做月度总额复核

先按物料或全口径聚合，确认差多少。

例如：

- `202601 -> 202602` 成品只差 `0.020t`
- `202603 -> 202604` 成品差 `2支 / 3.969t`

这一步只回答一个问题：

**到底是“大面积错”，还是“少数几条炉号造成的总差”。**

### 第 3 步：再下钻到炉号

总额确认后，一定要立刻切到炉号级。

因为物料级报错里，常见会混进：

- 改判
- 换物料编码
- 红冲
- 月末 0 支尾重
- 同炉号跨工序迁移

这些问题在物料级看起来像“差了很多”，但炉号级一拆就能分出：

- 真错
- 改判
- 历史残留

### 第 4 步：同一炉号同时看原表和 CX 表

每个异常炉号至少要看 2 套数据：

1. 原表  
   `YDM_*`

2. 中间表  
   `CX_*`

这一步的目的是把问题分型成：

- 原表错，CX 只是抄过去
- 原表已经对了，但 CX 还是旧值
- 原表没有，CX 多了
- 原表有，CX 漏了

### 第 5 步：看是不是“改判/换物料编码”

这一类在这次排查里占比很高。

表现形式通常是：

- 同一个炉号
- 上月在物料 A
- 下月或同月出库在物料 B

如果炉号本身是平的，只是物料变了，那通常不应该按“库存错误”处理，而应该按：

**改判说明**

### 第 6 步：看是不是“重复插入”

这次也遇到过非常典型的重复灌数：

- 原表应有 1 条
- `CX` 里被插了 4 次

这种问题最明显的特征是：

- 原表和业务逻辑都解释不出来这么大的数
- 同一炉号、同一月份、同一数量重量，`CX` 里出现多条

### 第 7 步：确定该改哪一层

这个很重要。

不是所有问题都该改原表。

判断规则：

- 原表正确，CX 错：改 `CX`
- 原表月份挂错：改原表，必要时同步 `CX`
- 属于改判：不改库存，出说明
- 属于月报算法问题：改过程逻辑或月报结果，不改收发存

### 第 8 步：修完以后一定复核

修完至少做 3 次复核：

1. 行级是否对平
2. 物料汇总是否对平
3. 相关校验过程重跑后是否符合预期


## 4. 这次遇到的典型错误类型与案例

下面把这两天碰到的典型问题，按类型整理。

---

## 4.1 期初带错

### 典型案例：半成品 202601 -> 202602

涉及炉号：

- `A26010132`
- `A26010135`
- `A26010139`
- `C26010317`

问题表现：

- `2026-01` 期末和 `2026-02` 期初对不上
- 这 4 个炉号在 `202602` 的 `YDM_BC_INITIAL` 被写成了“上月入库量”
- 不是“上月期末量”

例如：

`A26010132`

- 1 月实际期末：`1支 / 1.48吨`
- 2 月期初却写成：`64支 / 97.188吨`

最终处理：

- 修 `202602` 的 `YDM_BC_INITIAL`
- 再核 `202601 -> 202602 -> 202603 -> 202604`

经验结论：

**如果某月期初恰好等于上月某类入库，而不是上月期末，优先怀疑期初生成逻辑错把“入库承接”当成“结存承接”。**


## 4.2 原表已改正，CX 还停留在旧值

### 典型案例：`TQ9618310507410B`

涉及炉号：

- `A26010109`
- `A26010113`
- `A26010120`
- `A26010132`
- `A26010135`
- `A26010139`
- `C26010317`

问题表现：

- 当前原表已经改正
- 但 `CX_YDM_BC_*` 里还是旧数据
- 导致 `check_material_balance` 或 `DataValidationResult` 继续报错

处理方式：

- 不回头再改原表
- 直接把 `CX` 按当前原表同步

经验结论：

**先看“现在的原表”是不是已经对了，再决定要不要动源表。很多时候问题只是结果表没刷新。**


## 4.3 重复插入

### 典型案例：`TQ0218312001410B`

涉及炉号：

- `A25070249`
- `A25070271`
- `A25080210`

原表应有：

- `A25070249`：`1支 / 1.305吨`
- `A25070271`：`1支 / 1.646吨`
- `A25080210`：`2支 / 3.213吨`

`CX_YDM_BC_OUTLIST` 实际却是每条 4 次：

- `A25070249`：`4行 / 4支 / 5.220吨`
- `A25070271`：`4行 / 4支 / 6.584吨`
- `A25080210`：`4行 / 8支 / 12.852吨`

处理方式：

- 保留最早 1 条
- 删除后面 3 条重复数据

经验结论：

**同一炉号、同一月份、同一数量重量重复出现时，不要先怀疑业务，先怀疑 `CX` 持久化被重复执行。**


## 4.4 改判/换物料编码

### 典型案例 1：`TQ9618310507410B` 与 `TQ9618312007410B`

表现：

- 同一批炉号
- `2026-02` 在 `TQ9618312007410B`
- `2026-03` 期初挂到了 `TQ9618310507410B`

这类问题在物料级会表现为：

- 一个物料突然多
- 另一个物料突然少

但炉号级看是平的，只是物料变了。

这种情况更适合：

- 出“改判说明”
- 不按普通库存错账处理

### 典型案例 2：`TD0719312307411B`

涉及炉号：

- `C26010494`

历史 `CX` 快照里：

- `TD0719312307411B` 表面剩 `5支 / 12.618吨`
- 同炉号又有 `TQ5612412301411B` 出库 `5支 / 12.618吨`

这就是典型“同炉号跨物料改判”。

经验结论：

**只要同一炉号跨物料迁移且炉号级自平，优先归类为改判，不要急着补期初。**


## 4.5 尾重

### 典型案例 1：成品 `A22070051`

问题：

- `202601` 期末到 `202602` 期初只差 `0.020吨`

最后处理：

- 在 `YDM_ZC_STOCKTAKINGLIST` 补了一条 `202601` 调差
- 重量 `-0.02`
- 后来又把规格调整成正确的 `533.8x24.5`

### 典型案例 2：`TB8818212001411C`

涉及炉号：

- `A25050280`

原始情况：

- 期初：`1支 / 2.258吨`
- 负入库：`-1支 / -2.095吨`
- 导致期末形成 `0支 / 0.163吨` 尾重

处理方式：

- 把负入库重量改成和期初一致
- `-2.095 -> -2.258`

经验结论：

**只差零点几吨、支数为 0 的，优先按尾重处理。**


## 4.6 红冲导致跨月不平

### 典型案例：成品 `A25100221`、`A25100033`

表现：

- `202603` 没有期初、没有入库
- 但出现了 `800806` 负出库红冲

例如：

`A25100221`

- `2026-03` 出现 `800806 = -1支 / -2.265吨`
- 会把库存冲回成 `1支 / 2.265吨`
- 但 `202604` 期初没承接

`A25100033`

- `202602` 本来已清零
- `202603` 又有 `800806 = -1支 / -1.704吨`
- 又被冲回 `1支 / 1.704吨`
- `202604` 也没承接

经验结论：

**没有期初、没有入库，不代表不可能有库存。只要有负出库红冲，就可能把历史库存冲回来。**


## 4.7 月份挂错

### 典型案例：`TQ4577615272411B / C26030094`

问题：

- 月报里 `2026-03` 该有 `24支 / 23.233吨`
- `CX_YDM_BC_INLIST` 里只有 `12支 / 11.393吨`

后来追到原表发现：

- 另一半 `12条 / 11.84吨` 被挂在了 `202604`
- 实际应属于 `202603`

处理方式：

- 把原表 `YDM_BC_INLIST` 那 `12` 条的 `BAL_YEAR_MONTH`
  - `202604 -> 202603`
- 再同步 `CX`

处理后：

- 月报 `72.867`
- 台账 `72.867`
- 对平

经验结论：

**如果差值能完整在相邻月份找到，优先怀疑 `BAL_YEAR_MONTH` 挂错，而不是重量算错。**


## 4.8 月报来料重量算法错误

### 典型案例：加工月报 `TQ9618310507203B`

问题表：

- `HOT_PRODUCTION_MES_JG`
- 来源过程：`MES_CX_JG_ZXNEW_HAND`

异常表现：

- `mate_weight` 只有 `2~3吨`
- `prod_weight` 却有 `90~125吨`
- `steel_waste` 被算成 `3900%`

根因：

- 过程用的是  
  `mate_weight = sum(qcm.input_weight) + 接箍重量`
- 但这批 `G` 工序记录里，`QCM_ZG_JUGDE_APPLY.INPUT_WEIGHT` 大量为 0
- 结果只剩接箍重量

后来按你的业务逻辑核定：

**前一道工序的成品量 = 下一道工序的投料量**

示例：

`A24120546`

`D` 工序合计：

- `ACT_COUNT = 76`
- `ACT_WEIGHT = 94.992`

`G` 工序当前：

- `ACT_COUNT = 76`
- `ACT_WEIGHT = 99.307`
- `INPUT_WEIGHT = 0`

所以应补：

- `G.INPUT_WEIGHT = 94.992`

对应月报重算：

- 原 `MATE_WEIGHT = 2.509`
- 改后 `MATE_WEIGHT = 94.992 + 2.509 = 97.501`
- 原 `STEEL_WASTE = 3958.0311`
- 改后 `STEEL_WASTE = 101.8523`

最后处理：

- 改了 `QCM_ZG_JUGDE_APPLY`
- 同时改了 `HOT_PRODUCTION_MES_JG`
- 并做了可回滚备份

经验结论：

**月报“来料重量很离谱”时，不要直接改结果表，先追来源公式。**


## 4.9 接口重复接收与提单异常

### 典型案例：`KHFT260325016`

日志顺序：

1. `GetYdmZcBillDate`
2. `BillRevoke`
3. `GetYdmZcBillDate`

另外核到：

- 两次 `GetYdmZcBillDate` 的 `SOCKET_PARMER`
- 除 `planStartTime / planEndTime` 外，其余完全一致
- 也就是同一张提单被重复推送了一次

同时还发现：

- 提单主表曾出现过两条
- 明细只有 25 条，不是重复 50 条
- `BillClose` 传参里的炉号和库里的 `JUDGE_STOVE_NO` 对不上
- `YDM_ZC_BILL_C.LOADVEHICLE_FLAG` 还有 14 支没同步成已装车

经验结论：

**接口问题一定要同时看：接口日志、主表、明细表、装车表、代码匹配字段。只看一张表很容易误判。**


## 5. 如何判断“该补数据”还是“该出说明”

后面再碰到问题，可以直接按下面判断。

### 应该补数据

满足以下任一：

- 原表月份挂错
- `CX` 重复插入
- `CX` 漏同步
- 尾重非常明确，且能精确落到一条记录
- 红冲/调差值能明确定位到某行

### 不建议直接补数据

满足以下任一：

- 同炉号跨物料改判
- 月报来源逻辑本身不对
- 当前原表已经查不到来源，只剩历史快照
- 只能看出总差，无法落到具体炉号和具体行

### 应该出说明

满足以下任一：

- 炉号级平衡，只是物料编码变了
- 外部按物料汇总报错，但内部按炉号级不算错
- 第三方校验口径和系统口径不一致


## 6. 一个实战排查模板

后面你自己核某个问题，可以直接照这个顺序：

1. 先写下问题对象  
   物料、合同、月份、报错内容

2. 先做月度总额对账  
   `期初 + 入库 - 出库 (+ 调差) = 期末`

3. 再拆到炉号  
   找出差异是哪些炉号造成的

4. 同时查原表和 `CX`

5. 判断是以下哪类：
   - 期初带错
   - 原表已改，`CX` 未同步
   - 重复插入
   - 改判
   - 尾重
   - 红冲
   - 月份挂错
   - 月报算法问题
   - 接口重复或字段错配

6. 决定处理方式：
   - 改原表
   - 改 `CX`
   - 改月报来源表
   - 仅出说明

7. 修完后复核：
   - 行级
   - 炉号级
   - 物料级
   - 校验结果


## 7. 可直接复用的 SQL 思路

下面不是最终 SQL，只是核对时最常用的模式。

### 7.1 查某物料某月原表入出

```sql
select *
from ydm_bc_inlist t
where t.bal_year_month = '202603'
  and t.material_no = '物料编码';
```

```sql
select *
from ydm_bc_outlist t
where t.bal_year_month = '202603'
  and t.material_no = '物料编码';
```

### 7.2 查某炉号 1-4 月全链路

```sql
select 'INITIAL' src, t.bal_year_month, t.material_no, t.judge_stove_no,
       t.act_count, t.act_weight
from ydm_bc_initial t
where t.judge_stove_no = '炉号'
union all
select 'INLIST', t.bal_year_month, t.material_no, t.judge_stove_no,
       t.act_count, t.act_weight
from ydm_bc_inlist t
where t.judge_stove_no = '炉号'
union all
select 'OUTLIST', t.bal_year_month, t.material_no, t.judge_stove_no,
       t.act_count, t.act_weight
from ydm_bc_outlist t
where t.judge_stove_no = '炉号';
```

### 7.3 查原表和 CX 是否一致

做法不是只比汇总，而是至少比：

- 月份
- 物料
- 炉号
- 合同
- 支数
- 重量

如果汇总一样但明细不一样，后面还是会炸。


## 8. 这次已经被验证过的经验

最后把这两天最有用的结论压成几句话，后面很好用。

1. 先看炉号，再看物料。  
   很多“物料不连续”，其实是炉号改判。

2. 先看原表，再看 `CX`。  
   很多问题只是结果表旧了，不是源头错了。

3. 尾差优先看调差和红冲。  
   尤其是 `0支 非0吨`，十有八九不是正常库存。

4. 月报不要直接拿结果说话。  
   先搞清楚是从哪张判定表、按什么公式写出来的。

5. 接口问题一定要串日志、代码、数据库。  
   只看其中一块，很容易得出错结论。


## 9. 当前还值得继续追的点

截至当前，这几类仍然属于“后续可以继续排查”的方向：

- 当前库里完全没有、但外部说有的数据  
  例如某些销售结算接口物料

- 月报有值、原表当前查不到来源的数据  
  例如曾遇到的 `TQ5612510601412B`

- 改判链跨了多个月、当前只剩历史快照的数据

这类问题的共同点是：

**不能只靠当前原表，还要追历史快照、过程、接口源表。**


## 10. 一句话版总结

这两天所有问题，归根到底都是下面几类：

- 承接错
- 月份挂错
- `CX` 没同步
- `CX` 重复插入
- 红冲/尾重
- 改判
- 月报公式取错来源
- 接口重复推送或匹配字段不一致

只要后面排查时固定坚持：

**先总额、再炉号、再原表/CX 对照、最后再决定改数据还是出说明**

大多数问题都能很快定位清楚。
