# BD_Manual：修复 DWS_ASSISTANT_DAILY 缺失 table_area_name 列

> 影响任务：`DWS_ASSISTANT_DAILY`
> 涉及表：`dwd.dwd_assistant_service_log`（读取）、`dwd.dim_table`（新增 JOIN）、`dws.dws_assistant_daily`（写入）
> 修复日期：2026-02-26
> 代码位置：`apps/etl/connectors/feiqiu/tasks/dws/assistant_daily_task.py` → `_extract_service_records()`
> 触发场景：`FLOW_API_FULL` 执行时 DWS 阶段首个任务失败，级联导致后续 13 个 DWS 任务全部 `InFailedSqlTransaction`

---

## 1. 变更说明

`_extract_service_records()` 方法的 SQL 原先直接从 `dwd.dwd_assistant_service_log` 读取 `asl.table_area_name`，但该表实际不存在此列（DDL 可确认）。

修复方式：通过 LEFT JOIN `dwd.dim_table` 获取台区名称。

```sql
-- 修复前（错误）
SELECT ...
       asl.table_area_name,
       ...
FROM dwd.dwd_assistant_service_log asl
LEFT JOIN dwd.dwd_assistant_service_log_ex ex ...

-- 修复后（正确）
SELECT ...
       COALESCE(dt.site_table_area_name, '') AS table_area_name,
       ...
FROM dwd.dwd_assistant_service_log asl
LEFT JOIN dwd.dwd_assistant_service_log_ex ex ...
LEFT JOIN dwd.dim_table dt
    ON asl.site_table_id = dt.table_id
    AND dt.scd2_is_current = 1
```

JOIN 条件说明：
- `asl.site_table_id = dt.table_id`：通过台桌 ID 关联维度表
- `dt.scd2_is_current = 1`：仅取当前有效的 SCD2 版本
- `COALESCE(..., '')`：dim_table 无匹配时回退空字符串，避免 NULL 传播

---

## 2. 级联失败说明

此 bug 不仅导致 `DWS_ASSISTANT_DAILY` 本身失败，还因 DWS 阶段共享同一数据库连接且无逐任务 rollback，使 psycopg2 进入 `InFailedSqlTransaction` 状态，后续 13 个 DWS/INDEX 任务全部失败：

- DWS_ASSISTANT_CUSTOMER, DWS_ASSISTANT_SALARY, DWS_ASSISTANT_FINANCE, DWS_ASSISTANT_MONTHLY
- DWS_MEMBER_CONSUMPTION, DWS_MEMBER_VISIT
- DWS_FINANCE_DAILY, DWS_FINANCE_RECHARGE, DWS_FINANCE_INCOME_STRUCTURE, DWS_FINANCE_DISCOUNT_DETAIL
- DWS_WINBACK_INDEX, DWS_NEWCONV_INDEX, DWS_RELATION_INDEX

修复此根因后，上述任务均可恢复正常执行。

---

## 3. 兼容性影响

| 组件 | 影响 |
|------|------|
| ETL DWS 层 | `dws_assistant_daily` 恢复正常写入，`table_area_name` 来源从不存在的列改为 dim_table 维度表 |
| 后续 DWS 任务 | 级联失败消除，所有 DWS 任务可正常执行 |
| 后端 API | 无影响（DWS 聚合表结构未变） |
| 管理后台 | 助教日报表将正确显示台区名称 |
| DDL | 无变更，无新增表/列 |

---

## 4. 回滚策略

此修复仅涉及 Python 代码中的 SQL 查询，无 DDL 变更。

回滚步骤：
1. 将 `assistant_daily_task.py` 中 `_extract_service_records()` 的 SQL 恢复为 `asl.table_area_name`，移除 `LEFT JOIN dwd.dim_table`
2. 注意：回滚后 DWS_ASSISTANT_DAILY 将再次失败

已写入的 DWS 数据如需回滚：
```sql
-- 清除修复后写入的 dws_assistant_daily 数据（按需执行）
DELETE FROM dws.dws_assistant_daily
WHERE stat_date >= '2025-11-01';
```

---

## 5. 验证 SQL

```sql
-- 验证 1：确认 dwd_assistant_service_log 确实没有 table_area_name 列
SELECT column_name
FROM information_schema.columns
WHERE table_schema = 'dwd'
  AND table_name = 'dwd_assistant_service_log'
  AND column_name = 'table_area_name';
-- 预期：返回 0 行

-- 验证 2：确认 dim_table 存在 site_table_area_name 列
SELECT column_name
FROM information_schema.columns
WHERE table_schema = 'dwd'
  AND table_name = 'dim_table'
  AND column_name = 'site_table_area_name';
-- 预期：返回 1 行

-- 验证 3：检查 JOIN 关联覆盖率（service_log 的 site_table_id 在 dim_table 中的匹配率）
SELECT
    COUNT(*) AS total_records,
    COUNT(dt.table_id) AS matched_dim_table,
    ROUND(COUNT(dt.table_id)::numeric / NULLIF(COUNT(*), 0) * 100, 1) AS match_pct
FROM dwd.dwd_assistant_service_log asl
LEFT JOIN dwd.dim_table dt
    ON asl.site_table_id = dt.table_id
    AND dt.scd2_is_current = 1
WHERE asl.is_delete = 0;
-- 预期：match_pct 接近 100%

-- 验证 4：修复后重跑 ETL，检查 dws_assistant_daily 是否有数据
SELECT stat_date, COUNT(*) AS rows
FROM dws.dws_assistant_daily
WHERE stat_date >= '2025-11-01'
GROUP BY stat_date
ORDER BY stat_date
LIMIT 10;
-- 预期：有数据行返回
```

---

## 6. 代码引用

- 修复文件：`apps/etl/connectors/feiqiu/tasks/dws/assistant_daily_task.py` → `_extract_service_records()`
- 关联 BD Manual：`BD_Manual_assistant_service_records.md`（dwd_assistant_service_log 字段映射文档）
- dim_table DDL：`docs/database/ddl/etl_feiqiu__dwd.sql`（含 `site_table_area_name` 列定义）
