Files
SBrainCO/docs/智脑实施方法论/02-数据接入与治理.md
T
freedakgmail c2a9e27e49 docs: 新增智脑实施方法论文档体系(7篇) + fix: 态势感知关联分析修复
文档:
- 01-项目概述与架构: 技术架构、数据流、部署拓扑
- 02-数据接入与治理: 原始数据导入、物化视图、门店名映射
- 03-指标体系与API开发: 指标分层、SQL模式、常见陷阱
- 04-前端页面开发: 组件规范、页面模板、月份参数管理
- 05-部署与运维: 部署脚本、FRP隧道、PM2、备份
- 06-调试排查手册: 问题分类、8个实际案例、工具速查
- 07-通用方法论: 核心原则、实施阶段、快速复制Checklist

修复:
- situational-awareness.ts: salary_month→salary_period, 日期格式改中文
- 客流-人力匹配: 改用attendance_records打卡数据解析在岗人数
- 客流数据除以30天对齐日均
2026-08-12 11:00:54 +08:00

108 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 02 · 数据接入与治理
## 1. 原始数据导入
### 1.1 数据源
| 表名 | 数据来源 | 关键字段 | 数据量级 |
|------|---------|---------|---------|
| `bill_records` | 收银系统导出 | c003(门店) c005(账单号) c009(消费) c068(优惠) c114(实收) c175(下单时间) c176(结账时间) c191(收银员) | 千万级/月 |
| `salary_detail_records` | 薪资系统导出 | org_level5(门店) salary_period(薪资周期) actual_attend(实际出勤) actual_hours(实际工时) | 万级/月 |
| `attendance_records` | 考勤系统导出 | department(部门路径) position(岗位) day_01~day_31(每日打卡) | 万级/月 |
### 1.2 导入关键点
- **字段映射**:原始Excel列名(c001~c200)需建立映射文档,明确每列含义
- **日期格式**`salary_period` 格式为中文"2026年4月",非"2026-04",查询时需用 `to_char($1::date, 'YYYY"年"FMMM"月"')`
- **空值处理**:实收字段 c114 可能为空字符串,需 `COALESCE(NULLIF(c114,'')::numeric, 0)`
- **数据去重**:导入时按 record_id + import_id 去重
### 1.3 门店名映射
不同数据源门店名不一致,需维护 `store_name_mapping` 映射表:
```sql
CREATE TABLE public.store_name_mapping (
salary_name TEXT, -- 薪资/考勤系统中的名称
bill_name TEXT -- 账单系统中的名称
);
```
**典型映射**
| salary_name | bill_name |
|-------------|-----------|
| 双安店 | 双安总店 |
| 百子湾店 | 百子湾路店 |
| 安宁庄快手店 | 安宁庄快手 |
| 海淀大街店 | 海淀大街 |
| 哈马尔罕大钟寺店 | 大钟寺店 |
| 阿里疆(温泉路店) | 温泉店 |
**映射查找模式**(代码中复用):
```typescript
// 构建查找表:同时用原名和映射名
const staffLookup: Record<string, any> = {}
for (const [store, data] of Object.entries(staffSummary)) {
staffLookup[store] = data // 原名
const mapped = nameMap[store]
if (mapped && mapped !== store) {
staffLookup[mapped] = data // 映射名
}
}
```
## 2. 物化视图体系
### 2.1 核心物化视图
| 视图名 | Schema | 用途 | 关键字段 |
|--------|--------|------|---------|
| `mv_store_risk_rating_monthly` | analytics | 门店风险评级 | store_code, store_name, risk_level, received, month_start |
| `mv_store_platform_economics_monthly` | analytics | 平台经济性 | store_code, meituan_received, taobao_received, jd_received |
| `mv_bill_hourly` | public | 小时客流 | store_name, hour, bills, avg_guests |
| `mv_risk_anomaly` | public | 异常账单 | store_name, bill_no, consumption, anomaly_reason, month |
| `mv_risk_zero` | public | 零实收 | store_name, bill_no, zero_received_type, month |
| `mv_risk_cashier` | public | 收银员风险 | store_name, cashier, bill_count, anomaly_bills, month |
| `mv_channel_daily` | public | 支付渠道 | business_date, cash, alipay, wechat, meituan, month |
| `mv_time_hourly` | public | 时间维度汇总 | closing_hour, bill_count, received, month |
### 2.2 物化视图管理要点
1. **Schema前缀**:部分视图在 `analytics` schema,部分在 `public` schema,代码中需注意
2. **刷新机制**:物化视图需手动刷新 `REFRESH MATERIALIZED VIEW`,不自动更新
3. **索引**:重建物化视图后需重新创建索引
4. **阈值调优**:异常判断阈值需根据业务调整(如"消费-优惠与实收不平"阈值从0.05元提高到1元)
### 2.3 异常账单阈值设计
```sql
-- 异常类型判断(CASE WHEN顺序重要)
CASE
WHEN consumption > 0 AND received = 0 THEN '有消费无实收'
WHEN discount > consumption THEN '优惠大于消费'
WHEN abs(consumption - discount - received) > 1 THEN '消费-优惠与实收不平'
ELSE NULL
END
```
**关键教训**:阈值0.05元太严格,会将舍入差异标为异常。建议初始阈值设为1元,后续根据数据分布调整。
## 3. 数据质量校验
### 3.1 校验流程
1. **数据范围**`SELECT DISTINCT month FROM bill_records ORDER BY month` 确认最新月份
2. **门店数**`SELECT count(DISTINCT c003) FROM bill_records WHERE month = '2026-04'`
3. **金额一致性**`SELECT sum(c009), sum(c068), sum(c114)` 对比前后端
4. **物化视图刷新状态**:对比物化视图和原始表的记录数
### 3.2 常见数据问题
| 问题 | 症状 | 排查方法 |
|------|------|---------|
| 物化视图stale | API数据与数据库不一致 | 直接查原始表对比物化视图 |
| 月份格式不匹配 | 查询返回0条 | 检查 salary_period 实际格式 |
| 门店名不一致 | 部分门店无数据 | 对比不同表的门店名列表 |
| Schema前缀错误 | `relation does not exist` | 检查 `\dn``pg_matviews` |
| 列不存在 | `column does not exist` | 检查 `information_schema.columns` |