1223 lines
44 KiB
Markdown
1223 lines
44 KiB
Markdown
# MCP AI 查库手册
|
||
|
||
> **项目地址**:`apps/mcp-server`
|
||
> **目标用户**:AI 应用(阿里云百炼)通过 MCP 协议查询 PostgreSQL 数据库
|
||
> **数据库**:`etl_feiqiu`(ETL 数据仓库,六层架构)
|
||
> **服务地址**:`https://mcp.langlangzhuoqiu.cn/mcp`
|
||
|
||
---
|
||
|
||
## 概述
|
||
|
||
MCP Server 为 AI 应用提供 PostgreSQL 只读查询能力,专门用于查询台球门店的运营数据。通过标准化的工具接口,AI 可以快速获取会员信息、订单数据、助教业绩、财务汇总等业务数据,为智能分析和决策提供数据支撑。
|
||
|
||
### 架构流程
|
||
|
||
```
|
||
微信小程序 → 百炼 AI 应用 → MCP (HTTP) → MCP Server → PostgreSQL (etl_feiqiu)
|
||
```
|
||
|
||
---
|
||
|
||
## 可访问的数据库架构
|
||
|
||
### Schema 层次结构
|
||
|
||
| Schema | 层级 | 说明 | 表数量 | 主要用途 |
|
||
|--------|------|------|--------|---------|
|
||
| `ods` | 原始数据层 | 飞球 API 原始数据,JSON 结构保持 | 23 表 | 数据源头,保持原始格式 |
|
||
| `dwd` | 明细数据层 | 清洗后的业务明细,标准化字段 | 44 表 | 业务分析的基础数据 |
|
||
| `dws` | 汇总数据层 | 按日/月汇总的业绩指标 | 34 表 + 8 物化视图 | 报表和 KPI 分析 |
|
||
| `core` | 跨门店标准化 | 统一的维度表和标准化数据 | 7 表 | 多门店对比分析 |
|
||
| `meta` | 调度元数据 | ETL 任务执行状态和日志 | 3 表 | 数据质量监控 |
|
||
| `app` | 应用视图层 | 带 RLS 的业务视图 | 43 视图 | 应用层数据访问 |
|
||
|
||
### 数据隔离机制
|
||
|
||
- **多门店隔离**:所有业务表都有 `site_id` 字段,实现门店级数据隔离
|
||
- **RLS(行级安全)**:`app` schema 的视图层自动过滤当前用户可访问的门店数据
|
||
- **时间范围**:大部分汇总表按营业日(08:00 为分界点)进行数据归属
|
||
|
||
---
|
||
|
||
## MCP 工具详解
|
||
|
||
### 1. list_tables - 列出表清单
|
||
|
||
**功能**:获取指定 schema 下的所有表和视图
|
||
|
||
**参数**:
|
||
- `schema` (string, 默认 "dwd"): 目标 schema,可选值:`ods`/`dwd`/`dws`/`core`/`meta`/`app`
|
||
- `include_views` (boolean, 默认 false): 是否包含视图
|
||
|
||
**返回示例**:
|
||
```json
|
||
{
|
||
"schema": "dwd",
|
||
"include_views": false,
|
||
"tables": [
|
||
{"name": "dim_member", "type": "BASE TABLE"},
|
||
{"name": "dim_assistant", "type": "BASE TABLE"},
|
||
{"name": "dwd_order_head", "type": "BASE TABLE"}
|
||
],
|
||
"table_count": 44
|
||
}
|
||
```
|
||
|
||
**使用场景**:
|
||
- 探索某个层级有哪些可用的表
|
||
- 了解数据仓库的整体结构
|
||
- 查找特定业务域的相关表
|
||
|
||
### 2. describe_table - 查看表结构
|
||
|
||
**功能**:获取指定表的详细字段信息
|
||
|
||
**参数**:
|
||
- `table` (string, 必需): 表名
|
||
- `schema` (string, 默认 "dwd"): 所属 schema
|
||
|
||
**返回示例**:
|
||
```json
|
||
{
|
||
"schema": "dwd",
|
||
"table": "dim_member",
|
||
"columns": [
|
||
{
|
||
"name": "member_id",
|
||
"type": "bigint",
|
||
"nullable": "NO",
|
||
"default": null,
|
||
"position": 1
|
||
},
|
||
{
|
||
"name": "site_id",
|
||
"type": "bigint",
|
||
"nullable": "NO",
|
||
"default": null,
|
||
"position": 2
|
||
}
|
||
],
|
||
"column_count": 25
|
||
}
|
||
```
|
||
|
||
**使用场景**:
|
||
- 了解表的字段结构和数据类型
|
||
- 确认主键和外键字段
|
||
- 编写 SQL 查询前的字段确认
|
||
|
||
### 3. describe_schemas - 批量获取架构信息
|
||
|
||
**功能**:一次性获取多个 schema 的完整表结构信息,包含主键信息
|
||
|
||
**参数**:
|
||
- `schemas` (array, 可选): 目标 schema 列表,不传则返回全部六个 schema
|
||
- `include_views` (boolean, 默认 false): 是否包含视图
|
||
- `max_tables_per_schema` (integer, 默认 500): 每个 schema 最大返回表数量
|
||
|
||
**返回示例**:
|
||
```json
|
||
{
|
||
"schemas": {
|
||
"dwd": {
|
||
"table_count": 44,
|
||
"tables": {
|
||
"dim_member": {
|
||
"type": "BASE TABLE",
|
||
"primary_key": ["member_id"],
|
||
"columns": [
|
||
{
|
||
"name": "member_id",
|
||
"type": "bigint",
|
||
"nullable": "NO",
|
||
"default": null,
|
||
"position": 1
|
||
}
|
||
],
|
||
"column_count": 25
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"include_views": false,
|
||
"limits": {"max_tables_per_schema": 500}
|
||
}
|
||
```
|
||
|
||
**使用场景**:
|
||
- 快速了解整个数据仓库的结构
|
||
- 获取表间关联关系(通过主键信息)
|
||
- 为复杂查询做准备
|
||
|
||
### 4. query_sql - 执行 SQL 查询
|
||
|
||
**功能**:在指定 schema 内执行只读 SQL 查询
|
||
|
||
**参数**:
|
||
- `schema` (string, 必需): 执行查询的 schema
|
||
- `sql` (string, 必需): SQL 查询语句
|
||
- `max_rows` (integer, 默认 500): 最大返回行数
|
||
|
||
**安全限制**:
|
||
- 仅允许 SELECT、WITH、SHOW、EXPLAIN 语句
|
||
- 禁止 DDL/DML 操作(CREATE、DROP、INSERT、UPDATE、DELETE 等)
|
||
- 限制跨 schema 引用(仅允许在指定 schema 内查询)
|
||
- 自动设置 `search_path` 到指定 schema
|
||
|
||
**返回示例**:
|
||
```json
|
||
{
|
||
"schema": "dwd",
|
||
"columns": ["member_id", "real_name", "mobile", "site_id"],
|
||
"rows": [
|
||
[2947562271297029, "张三", "13800138000", 1001],
|
||
[2947562271297030, "李四", "13800138001", 1001]
|
||
],
|
||
"row_count": 2,
|
||
"truncated": false,
|
||
"max_rows": 500
|
||
}
|
||
```
|
||
|
||
**使用场景**:
|
||
- 执行具体的业务查询
|
||
- 获取统计分析数据
|
||
- 验证数据质量和完整性
|
||
|
||
---
|
||
|
||
## 核心业务表详解
|
||
|
||
### 会员相关表
|
||
|
||
#### dwd.dim_member - 会员主档
|
||
**业务含义**:会员基础信息维度表,包含会员的身份信息、联系方式、等级状态等
|
||
|
||
**关键字段**:
|
||
- `member_id` (BIGINT): 会员唯一标识,飞球系统雪花 ID
|
||
- `site_id` (BIGINT): 所属门店 ID,多门店隔离关键字段
|
||
- `real_name` (TEXT): 会员真实姓名
|
||
- `mobile` (TEXT): 手机号,11 位格式
|
||
- `member_no` (TEXT): 会员编号,门店内序号
|
||
- `level` (INTEGER): 会员等级,对应不同的服务权益
|
||
- `birthday` (DATE): 生日,用于生日营销
|
||
- `gender` (INTEGER): 性别,0=未设置,1=男,2=女
|
||
- `balance` (NUMERIC): 账户余额,单位元,精度到分
|
||
- `member_status` (INTEGER): 会员状态,1=正常,2=冻结
|
||
- `create_time` (TIMESTAMPTZ): 注册时间
|
||
- `scd2_is_current` (INTEGER): SCD2 当前版本标记,1=当前,0=历史
|
||
|
||
**查询示例**:
|
||
```sql
|
||
-- 查询某门店的活跃会员
|
||
SELECT member_id, real_name, mobile, balance, level
|
||
FROM dim_member
|
||
WHERE site_id = 1001
|
||
AND member_status = 1
|
||
AND scd2_is_current = 1
|
||
ORDER BY create_time DESC
|
||
LIMIT 10;
|
||
```
|
||
|
||
#### dwd.dwd_member_balance_change - 会员余额变动
|
||
**业务含义**:记录会员账户余额的每一笔变动,包括充值、消费、退款、系统调整等,支持本金和赠送金分别记录
|
||
|
||
**关键字段**:
|
||
- `balance_change_id` (BIGINT): 变动记录唯一标识(主键)
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `tenant_member_id` (BIGINT): 租户维度会员 ID
|
||
- `system_member_id` (BIGINT): 系统维度会员 ID(跨租户唯一)
|
||
- `member_name` (VARCHAR): 会员姓名快照
|
||
- `member_mobile` (VARCHAR): 会员手机号快照
|
||
- `from_type` (INTEGER): 变动来源类型,1=结算扣款,2=充值,3=退款返还,4=系统调整,7=转账,9=其他
|
||
- `balance_before` (NUMERIC): 变动前余额(元)
|
||
- `change_amount` (NUMERIC): 变动金额(元),正数为充入,负数为扣减
|
||
- `balance_after` (NUMERIC): 变动后余额(元)
|
||
- `principal_before` (NUMERIC): 变动前本金余额(元),不含赠送金
|
||
- `principal_after` (NUMERIC): 变动后本金余额(元)
|
||
- `principal_change_amount` (NUMERIC): 本金变动金额(元)
|
||
- `payment_method` (INTEGER): 支付方式
|
||
- `change_time` (TIMESTAMPTZ): 变动发生时间
|
||
- `relate_id` (BIGINT): 关联业务单据 ID,按 from_type 指向不同表
|
||
- `operator_name` (VARCHAR): 操作员姓名
|
||
- `remark` (VARCHAR): 备注说明
|
||
|
||
**查询示例**:
|
||
```sql
|
||
-- 查询某会员的余额变动历史
|
||
SELECT
|
||
change_time,
|
||
from_type,
|
||
change_amount,
|
||
balance_before,
|
||
balance_after,
|
||
remark
|
||
FROM dwd_member_balance_change
|
||
WHERE site_id = 1001
|
||
AND tenant_member_id = 2947562271297029
|
||
ORDER BY change_time DESC
|
||
LIMIT 20;
|
||
```
|
||
|
||
### 订单相关表
|
||
|
||
#### dwd.dwd_order_head - 订单主表
|
||
**业务含义**:台球消费订单的主要信息,记录每次消费的基本情况
|
||
|
||
**关键字段**:
|
||
- `order_id` (BIGINT): 订单唯一标识
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `member_id` (BIGINT): 消费会员 ID,0 表示散客
|
||
- `table_id` (BIGINT): 台桌 ID
|
||
- `assistant_id` (BIGINT): 服务助教 ID
|
||
- `order_status` (INTEGER): 订单状态,1=进行中,2=已结算,3=已取消
|
||
- `start_time` (TIMESTAMPTZ): 开台时间
|
||
- `end_time` (TIMESTAMPTZ): 结台时间
|
||
- `duration_minutes` (INTEGER): 消费时长(分钟)
|
||
- `total_amount` (NUMERIC): 订单总金额
|
||
- `table_fee` (NUMERIC): 台费
|
||
- `service_fee` (NUMERIC): 服务费
|
||
- `goods_amount` (NUMERIC): 商品金额
|
||
- `discount_amount` (NUMERIC): 优惠金额
|
||
- `actual_amount` (NUMERIC): 实付金额
|
||
|
||
**查询示例**:
|
||
```sql
|
||
-- 查询某门店今日订单统计
|
||
SELECT
|
||
COUNT(*) as order_count,
|
||
SUM(actual_amount) as total_revenue,
|
||
AVG(duration_minutes) as avg_duration
|
||
FROM dwd_order_head
|
||
WHERE site_id = 1001
|
||
AND DATE(start_time) = CURRENT_DATE
|
||
AND order_status = 2;
|
||
```
|
||
|
||
#### dwd.dwd_settlement_head - 结算主表
|
||
**业务含义**:订单的结算信息,包含支付方式、优惠使用等详细信息
|
||
|
||
**关键字段**:
|
||
- `settlement_id` (BIGINT): 结算记录唯一标识
|
||
- `order_id` (BIGINT): 关联订单 ID
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `member_id` (BIGINT): 会员 ID
|
||
- `settle_type` (INTEGER): 结算类型,1=正常消费,3=退款,5=充值
|
||
- `pay_method` (INTEGER): 支付方式,1=现金,2=微信,3=支付宝,4=余额
|
||
- `total_amount` (NUMERIC): 结算总金额
|
||
- `discount_amount` (NUMERIC): 优惠金额
|
||
- `actual_amount` (NUMERIC): 实付金额
|
||
- `settle_time` (TIMESTAMPTZ): 结算时间
|
||
|
||
### 助教相关表
|
||
|
||
#### dwd.dim_assistant - 助教主档
|
||
**业务含义**:助教基础信息维度表,记录助教的身份和工作信息
|
||
|
||
**关键字段**:
|
||
- `assistant_id` (BIGINT): 助教唯一标识
|
||
- `site_id` (BIGINT): 所属门店 ID
|
||
- `assistant_no` (TEXT): 助教编号,门店内序号
|
||
- `real_name` (TEXT): 助教真实姓名
|
||
- `nickname` (TEXT): 昵称,用于小程序展示
|
||
- `mobile` (TEXT): 手机号
|
||
- `level` (INTEGER): 助教等级,对应技能水平
|
||
- `team_id` (BIGINT): 所属团队 ID,0 表示未分组
|
||
- `team_name` (TEXT): 团队名称
|
||
- `entry_time` (TIMESTAMPTZ): 入职时间
|
||
- `resign_time` (TIMESTAMPTZ): 离职时间,NULL 表示在职
|
||
- `leave_status` (INTEGER): 在职状态,0=在职,1=已离职
|
||
- `assistant_status` (INTEGER): 助教状态,1=正常,2=停用
|
||
|
||
#### dwd.dwd_assistant_service_log - 助教服务记录
|
||
**业务含义**:记录助教的每次服务活动,包含陪打和促销两种服务类型,用于业绩统计和服务质量分析
|
||
|
||
**关键字段**:
|
||
- `assistant_service_id` (BIGINT): 服务记录唯一标识(主键)
|
||
- `order_trade_no` (BIGINT): 关联的订单交易号
|
||
- `site_assistant_id` (BIGINT): 门店维度助教档案 ID,关联 dim_assistant.assistant_id
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `tenant_member_id` (BIGINT): 租户维度会员 ID
|
||
- `order_assistant_type` (INTEGER): 助教服务类型,1=陪打,2=促销
|
||
- `assistant_no` (VARCHAR): 助教编号(门店内序号)
|
||
- `nickname` (VARCHAR): 助教昵称
|
||
- `level_name` (VARCHAR): 助教等级名称,如"高级"、"中级"
|
||
- `skill_name` (VARCHAR): 服务技能名称,如"陪打"、"促销"
|
||
- `ledger_unit_price` (NUMERIC): 分账单价(元/小时)
|
||
- `ledger_amount` (NUMERIC): 分账总金额(元)
|
||
- `real_service_money` (NUMERIC): 实际服务金额(元),扣除折扣后的实收
|
||
- `income_seconds` (INTEGER): 计费时长(秒)
|
||
- `real_use_seconds` (INTEGER): 实际使用时长(秒)
|
||
- `start_use_time` (TIMESTAMPTZ): 服务开始时间
|
||
- `last_use_time` (TIMESTAMPTZ): 服务结束时间
|
||
- `composite_grade` (NUMERIC): 综合评分,如 4.50
|
||
- `is_trash` (INTEGER): 是否已废除,0=正常,1=已废除
|
||
- `trash_reason` (VARCHAR): 废除原因
|
||
|
||
### 台桌相关表
|
||
|
||
#### dwd.dim_table - 台桌维表
|
||
**业务含义**:门店台桌基础信息维度表,记录每个台桌的基本配置、区域归属、价格等信息
|
||
|
||
**关键字段**:
|
||
- `table_id` (BIGINT): 台桌唯一标识(主键)
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `table_name` (TEXT): 台桌名称,如"1号台"、"VIP1"
|
||
- `site_table_area_id` (BIGINT): 门店台桌区域 ID
|
||
- `site_table_area_name` (TEXT): 台桌区域名称,如"大厅"、"VIP区"
|
||
- `table_price` (NUMERIC): 台费单价(元/小时)
|
||
- `order_id` (BIGINT): 当前关联的订单 ID,0表示空闲
|
||
- `table_status` (INTEGER): 台桌状态枚举
|
||
- `is_online_reservation` (INTEGER): 是否支持在线预约,0=否,1=是
|
||
- `light_status` (INTEGER): 台灯状态,1=已关灯,2=已开灯
|
||
- `charge_free` (INTEGER): 是否免费台,0=收费,1=免费
|
||
- `virtual_table` (INTEGER): 是否虚拟台桌,0=实体台,1=虚拟台
|
||
- `applet_qr_code_url` (TEXT): 小程序二维码 URL,用于扫码开台
|
||
- `delay_lights_time` (INTEGER): 台灯熄灭延迟时间(秒)
|
||
|
||
**查询示例**:
|
||
```sql
|
||
-- 查询某门店的台桌使用情况
|
||
SELECT
|
||
table_name,
|
||
site_table_area_name,
|
||
table_price,
|
||
CASE WHEN order_id = 0 THEN '空闲' ELSE '使用中' END as status,
|
||
light_status
|
||
FROM dim_table
|
||
WHERE site_id = 1001
|
||
AND scd2_is_current = 1
|
||
ORDER BY site_table_area_name, table_name;
|
||
```
|
||
|
||
### 商品库存相关表
|
||
|
||
#### dwd.dim_store_goods - 门店商品档案
|
||
**业务含义**:门店级商品主档,记录每个门店销售的商品基本信息、价格、库存状态等
|
||
|
||
**关键字段**:
|
||
- `site_goods_id` (BIGINT): 门店商品唯一标识(主键)
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `tenant_goods_id` (BIGINT): 租户商品 ID,关联 dim_tenant_goods
|
||
- `goods_name` (TEXT): 商品名称,如"百威啤酒"
|
||
- `goods_category_id` (BIGINT): 一级分类 ID
|
||
- `goods_second_category_id` (BIGINT): 二级分类 ID
|
||
- `category_level1_name` (TEXT): 一级分类名称,如"酒水"
|
||
- `category_level2_name` (TEXT): 二级分类名称,如"啤酒"
|
||
- `sale_price` (NUMERIC): 商品售价(元)
|
||
- `cost_price` (NUMERIC): 成本价(元)
|
||
- `stock_qty` (INTEGER): 当前库存数量(实时库存)
|
||
- `batch_stock_qty` (INTEGER): 批次库存数量(按批次管理的库存)
|
||
- `safety_stock_qty` (INTEGER): 安全库存数量(低于此值触发预警)
|
||
- `sale_qty` (INTEGER): 累计销售数量
|
||
- `avg_monthly_sales` (NUMERIC): 月均销量
|
||
- `goods_state` (INTEGER): 商品状态
|
||
- `not_sale` (INTEGER): 是否停售,0=在售,1=停售
|
||
- `is_discountable` (INTEGER): 是否可打折,0=不可,1=可
|
||
- `unit` (TEXT): 计量单位,如"瓶"、"包"
|
||
- `commodity_code` (TEXT): 商品编码
|
||
|
||
#### dwd.dwd_goods_stock_movement - 库存变动流水
|
||
**业务含义**:记录商品库存的每一笔变动,包括销售出库、采购入库、退货、领用等
|
||
|
||
**关键字段**:
|
||
- `site_goods_stock_id` (BIGINT): 库存变动记录唯一标识(主键)
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `site_goods_id` (BIGINT): 门店商品 ID,关联 dim_store_goods
|
||
- `goods_name` (TEXT): 商品名称
|
||
- `stock_type` (INTEGER): 库存变动类型,1=销售出库,2=采购入库,4=退货入库,7=采购退货,8=领用出库,9=领用退回
|
||
- `change_num` (NUMERIC): 变动数量(正数为增加,负数为减少)
|
||
- `start_num` (NUMERIC): 变动前库存量
|
||
- `end_num` (NUMERIC): 变动后库存量
|
||
- `price` (NUMERIC): 商品单价(元)
|
||
- `operator_name` (TEXT): 操作人姓名
|
||
- `create_time` (TIMESTAMPTZ): 变动发生时间
|
||
- `remark` (TEXT): 备注说明,如"结账退货"、"采购退货"、"系统自动领用"
|
||
|
||
**查询示例**:
|
||
```sql
|
||
-- 查询某商品的库存变动历史
|
||
SELECT
|
||
create_time,
|
||
stock_type,
|
||
change_num,
|
||
start_num,
|
||
end_num,
|
||
operator_name,
|
||
remark
|
||
FROM dwd_goods_stock_movement
|
||
WHERE site_id = 1001
|
||
AND goods_name LIKE '%百威%'
|
||
ORDER BY create_time DESC
|
||
LIMIT 20;
|
||
```
|
||
|
||
#### dwd.dwd_recharge_order - 充值订单
|
||
**业务含义**:记录会员充值的详细信息,包括充值金额、支付方式、优惠活动等
|
||
|
||
**关键字段**:
|
||
- `recharge_order_id` (BIGINT): 充值记录唯一标识(主键)
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `member_id` (BIGINT): 会员 ID
|
||
- `member_name_snapshot` (TEXT): 会员姓名快照
|
||
- `member_phone_snapshot` (TEXT): 会员手机号快照
|
||
- `tenant_member_card_id` (BIGINT): 会员卡 ID
|
||
- `member_card_type_name` (TEXT): 会员卡类型名称,如"普通会员卡"
|
||
- `settle_type` (INTEGER): 结算类型枚举
|
||
- `is_first` (INTEGER): 是否首次充值,0=否,1=是
|
||
- `pay_amount` (NUMERIC): 实付金额(元)
|
||
- `cash_amount` (NUMERIC): 现金支付金额(元)
|
||
- `online_amount` (NUMERIC): 线上支付金额(元)
|
||
- `balance_amount` (NUMERIC): 余额支付金额(元)
|
||
- `payment_method` (TEXT): 支付方式,如"微信"、"支付宝"
|
||
- `create_time` (TIMESTAMPTZ): 充值记录创建时间
|
||
- `pay_time` (TIMESTAMPTZ): 支付完成时间
|
||
- `is_activity` (BOOLEAN): 是否参与活动
|
||
- `is_use_coupon` (BOOLEAN): 是否使用优惠券
|
||
- `operator_name_snapshot` (TEXT): 操作员姓名快照
|
||
|
||
#### dwd.dim_tenant_goods - 租户商品档案
|
||
**业务含义**:租户级商品主档,记录租户下所有商品的基本信息,是门店商品的上级概念
|
||
|
||
**关键字段**:
|
||
- `tenant_goods_id` (BIGINT): 租户商品唯一标识(主键)
|
||
- `tenant_id` (BIGINT): 租户 ID
|
||
- `supplier_id` (BIGINT): 供应商 ID
|
||
- `goods_name` (VARCHAR): 商品名称,如"百威啤酒"
|
||
- `goods_number` (VARCHAR): 商品编号
|
||
- `category_name` (VARCHAR): 一级分类名称,如"酒水"
|
||
- `goods_category_id` (BIGINT): 一级分类 ID
|
||
- `goods_second_category_id` (BIGINT): 二级分类 ID
|
||
- `unit` (VARCHAR): 计量单位,如"瓶"、"包"
|
||
- `market_price` (NUMERIC): 市场价/建议售价(元)
|
||
- `cost_price` (NUMERIC): 成本价(元)
|
||
- `min_discount_price` (NUMERIC): 最低折扣价(元)
|
||
- `goods_state` (INTEGER): 商品状态
|
||
- `not_sale` (INTEGER): 是否停售,0=在售,1=停售
|
||
- `able_discount` (INTEGER): 是否允许折扣,0=不允许,1=允许
|
||
- `is_warehousing` (INTEGER): 是否入库管理,0=否,1=是
|
||
- `goods_bar_code` (VARCHAR): 商品条码
|
||
- `commodity_code_list` (TEXT[]): 商品编码数组
|
||
- `pinyin_initial` (VARCHAR): 商品名称拼音首字母,用于快速检索
|
||
|
||
#### dwd.dwd_goods_stock_summary - 库存汇总快照
|
||
**业务含义**:按时间窗口汇总的商品库存变动统计,记录期初期末库存、进销存数据
|
||
|
||
**关键字段**:
|
||
- `site_goods_id` (BIGINT): 门店商品 ID(主键之一)
|
||
- `fetched_at` (TIMESTAMPTZ): ETL采集时间戳(主键之一)
|
||
- `goods_name` (TEXT): 商品名称
|
||
- `goods_unit` (TEXT): 计量单位
|
||
- `category_name` (TEXT): 一级分类名称
|
||
- `range_start_stock` (NUMERIC): 期初库存(查询时间窗口起点的库存量)
|
||
- `range_end_stock` (NUMERIC): 期末库存(查询时间窗口终点的库存量)
|
||
- `range_in` (NUMERIC): 入库数量(采购/调拨入库总量)
|
||
- `range_out` (NUMERIC): 出库数量(调拨出库/报损总量)
|
||
- `range_sale` (NUMERIC): 销售数量(销售出库总量)
|
||
- `range_sale_money` (NUMERIC): 销售金额(元)
|
||
- `range_inventory` (NUMERIC): 盘点调整量(盘盈/盘亏净量)
|
||
- `current_stock` (NUMERIC): 当前库存(API返回时的实时库存量)
|
||
|
||
### 小程序业务表(zqyy_app.biz Schema)
|
||
|
||
#### biz.coach_tasks - 助教任务表
|
||
**业务含义**:小程序助教任务系统的核心表,记录任务分配、状态、有效期、置顶、放弃原因等
|
||
|
||
**关键字段**:
|
||
- `id` (BIGSERIAL): 自增主键
|
||
- `site_id` (BIGINT): 门店 ID(多门店隔离)
|
||
- `assistant_id` (BIGINT): 助教 ID
|
||
- `member_id` (BIGINT): 客户 ID
|
||
- `task_type` (VARCHAR): 任务类型,high_priority_recall/priority_recall/follow_up_visit/relationship_building
|
||
- `status` (VARCHAR): 状态,active/inactive/completed/abandoned
|
||
- `priority_score` (NUMERIC): 优先级分数,取 max(WBI, NCI) 快照
|
||
- `expires_at` (TIMESTAMPTZ): 有效期时间戳,NULL表示无限期
|
||
- `is_pinned` (BOOLEAN): 是否置顶
|
||
- `abandon_reason` (TEXT): 放弃原因(放弃时必填)
|
||
- `completed_at` (TIMESTAMPTZ): 完成时间
|
||
- `parent_task_id` (BIGINT): 父任务 ID(自引用)
|
||
|
||
#### biz.notes - 统一备注表
|
||
**业务含义**:小程序备注系统,通过 type 字段区分普通备注/回访备注/放弃原因,含星星评分
|
||
|
||
**关键字段**:
|
||
- `id` (BIGSERIAL): 自增主键
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `user_id` (INTEGER): 小程序用户 ID
|
||
- `target_type` (VARCHAR): 目标类型(如 member)
|
||
- `target_id` (BIGINT): 目标 ID(如 member_id)
|
||
- `type` (VARCHAR): 备注类型,normal/follow_up/abandon_reason
|
||
- `content` (TEXT): 备注内容
|
||
- `rating_service_willingness` (SMALLINT): 再次服务意愿评分(1-5)
|
||
- `rating_revisit_likelihood` (SMALLINT): 再来店可能性评分(1-5)
|
||
- `task_id` (BIGINT): 关联任务 ID
|
||
- `ai_score` (SMALLINT): AI应用6评分(P5实现)
|
||
- `ai_analysis` (TEXT): AI分析结果(P5实现)
|
||
|
||
#### biz.trigger_jobs - 触发器配置表
|
||
**业务含义**:存储 cron/interval/event 三种触发方式的配置与执行状态
|
||
|
||
**关键字段**:
|
||
- `id` (SERIAL): 自增主键
|
||
- `job_type` (VARCHAR): 任务类型标识,映射到 Python handler
|
||
- `job_name` (VARCHAR): 任务名称(唯一)
|
||
- `trigger_condition` (VARCHAR): 触发方式,cron/interval/event
|
||
- `trigger_config` (JSONB): 触发配置(cron表达式/间隔秒数/事件名)
|
||
- `last_run_at` (TIMESTAMPTZ): 上次运行时间
|
||
- `next_run_at` (TIMESTAMPTZ): 下次运行时间(event类型为NULL)
|
||
- `status` (VARCHAR): 状态,enabled/disabled
|
||
|
||
**查询示例**:
|
||
```sql
|
||
-- 查询助教的活跃任务
|
||
SELECT
|
||
t.task_type,
|
||
m.real_name as member_name,
|
||
t.priority_score,
|
||
t.expires_at,
|
||
t.is_pinned,
|
||
t.created_at
|
||
FROM biz.coach_tasks t
|
||
JOIN dim_member m ON t.member_id = m.member_id AND t.site_id = m.site_id
|
||
WHERE t.site_id = 1001
|
||
AND t.assistant_id = 2947562271297029
|
||
AND t.status = 'active'
|
||
AND m.scd2_is_current = 1
|
||
ORDER BY t.is_pinned DESC, t.priority_score DESC;
|
||
```
|
||
|
||
#### dws.dws_member_daily_summary - 会员日汇总
|
||
**业务含义**:按会员和日期汇总的消费数据,用于会员行为分析
|
||
|
||
**关键字段**:
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `member_id` (BIGINT): 会员 ID
|
||
- `stat_date` (DATE): 统计日期(营业日)
|
||
- `visit_count` (INTEGER): 到店次数
|
||
- `order_count` (INTEGER): 消费笔数
|
||
- `total_amount` (NUMERIC): 消费总金额
|
||
- `table_fee` (NUMERIC): 台费总额
|
||
- `service_fee` (NUMERIC): 服务费总额
|
||
- `goods_amount` (NUMERIC): 商品消费总额
|
||
- `play_minutes` (INTEGER): 游戏时长(分钟)
|
||
- `avg_order_amount` (NUMERIC): 平均客单价
|
||
|
||
#### dws.dws_assistant_daily_detail - 助教日业绩明细
|
||
**业务含义**:按助教和日期汇总的业绩数据,用于助教绩效考核
|
||
|
||
**关键字段**:
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `assistant_id` (BIGINT): 助教 ID
|
||
- `stat_date` (DATE): 统计日期
|
||
- `service_count` (INTEGER): 服务次数
|
||
- `service_minutes` (INTEGER): 服务时长
|
||
- `service_revenue` (NUMERIC): 服务收入
|
||
- `member_count` (INTEGER): 服务会员数
|
||
- `avg_rating` (NUMERIC): 平均评分
|
||
- `new_member_count` (INTEGER): 新增会员数
|
||
- `repeat_member_count` (INTEGER): 复购会员数
|
||
|
||
#### dws.dws_assistant_order_contribution - 助教订单贡献统计
|
||
**业务含义**:助教订单流水四项统计,用于精确计算助教的业绩贡献,支持多种分成模式
|
||
|
||
**关键字段**:
|
||
- `contribution_id` (BIGINT): 记录唯一标识,自增主键
|
||
- `site_id` (INTEGER): 门店 ID
|
||
- `assistant_id` (BIGINT): 助教 ID
|
||
- `assistant_nickname` (VARCHAR): 助教昵称
|
||
- `stat_date` (DATE): 统计日期
|
||
- `order_gross_revenue` (NUMERIC): 订单总流水 = 台费 + 酒水食品 + 所有助教服务费
|
||
- `order_net_revenue` (NUMERIC): 订单净流水 = 订单总流水 - 所有助教服务分成
|
||
- `time_weighted_revenue` (NUMERIC): 时效贡献流水 = 台费按时长分摊 + 个人服务费 + 酒水食品按时长比例
|
||
- `time_weighted_net_revenue` (NUMERIC): 时效净贡献 = 时效贡献流水 - 个人服务分成
|
||
- `order_count` (INTEGER): 当日参与订单数
|
||
- `total_service_seconds` (INTEGER): 当日总服务时长(秒)
|
||
|
||
**四项统计说明**:
|
||
1. **订单总流水**:助教参与的所有订单的总收入,每个参与助教获得相同值
|
||
2. **订单净流水**:扣除所有助教分成后的净收入,每个参与助教获得相同值
|
||
3. **时效贡献流水**:按服务时长比例分摊的收入,体现个人贡献度
|
||
4. **时效净贡献**:扣除个人分成后的净贡献,最终的业绩指标
|
||
|
||
**查询示例**:
|
||
```sql
|
||
-- 助教业绩四项统计对比
|
||
SELECT
|
||
assistant_nickname,
|
||
stat_date,
|
||
order_gross_revenue,
|
||
order_net_revenue,
|
||
time_weighted_revenue,
|
||
time_weighted_net_revenue,
|
||
order_count,
|
||
total_service_seconds/3600.0 as service_hours
|
||
FROM dws_assistant_order_contribution
|
||
WHERE site_id = 1001
|
||
AND stat_date >= CURRENT_DATE - INTERVAL '7 days'
|
||
ORDER BY stat_date DESC, time_weighted_net_revenue DESC;
|
||
```
|
||
|
||
#### dws.dws_goods_stock_daily_summary - 商品库存日汇总
|
||
**业务含义**:按日汇总的商品库存变动统计,用于库存分析和补货决策
|
||
|
||
**关键字段**:
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `stat_date` (DATE): 统计日期
|
||
- `site_goods_id` (BIGINT): 门店商品 ID
|
||
- `goods_name` (TEXT): 商品名称
|
||
- `goods_unit` (TEXT): 计量单位
|
||
- `category_name` (TEXT): 一级分类名称
|
||
- `range_start_stock` (NUMERIC): 期初库存,统计日期开始时的库存量
|
||
- `range_end_stock` (NUMERIC): 期末库存,统计日期结束时的库存量
|
||
- `range_in` (NUMERIC): 入库数量,采购/调拨入库总量
|
||
- `range_out` (NUMERIC): 出库数量,调拨出库/报损总量
|
||
- `range_sale` (NUMERIC): 销售数量,销售出库总量
|
||
- `range_sale_money` (NUMERIC): 销售金额,销售总金额
|
||
- `range_inventory` (NUMERIC): 盘点调整量,盘盈/盘亏净量
|
||
- `current_stock` (NUMERIC): 当前库存,统计日期末的实时库存量
|
||
- `stat_period` (TEXT): 汇总粒度标识,'daily'
|
||
|
||
**查询示例**:
|
||
```sql
|
||
-- 商品库存变动分析
|
||
SELECT
|
||
goods_name,
|
||
category_name,
|
||
range_start_stock,
|
||
range_in,
|
||
range_sale,
|
||
range_out,
|
||
range_end_stock,
|
||
range_sale_money,
|
||
CASE
|
||
WHEN range_sale > 0 THEN range_sale_money / range_sale
|
||
ELSE 0
|
||
END as avg_sale_price
|
||
FROM dws_goods_stock_daily_summary
|
||
WHERE site_id = 1001
|
||
AND stat_date = CURRENT_DATE - INTERVAL '1 day'
|
||
AND (range_in > 0 OR range_sale > 0 OR range_out > 0)
|
||
ORDER BY range_sale_money DESC;
|
||
|
||
-- 库存周转率分析
|
||
SELECT
|
||
goods_name,
|
||
category_name,
|
||
AVG(range_start_stock + range_end_stock) / 2 as avg_stock,
|
||
SUM(range_sale) as total_sale,
|
||
CASE
|
||
WHEN AVG(range_start_stock + range_end_stock) > 0
|
||
THEN SUM(range_sale) / (AVG(range_start_stock + range_end_stock) / 2)
|
||
ELSE 0
|
||
END as turnover_rate
|
||
FROM dws_goods_stock_daily_summary
|
||
WHERE site_id = 1001
|
||
AND stat_date >= CURRENT_DATE - INTERVAL '30 days'
|
||
GROUP BY site_goods_id, goods_name, category_name
|
||
HAVING SUM(range_sale) > 0
|
||
ORDER BY turnover_rate DESC;
|
||
```
|
||
|
||
#### dws.dws_assistant_order_contribution - 助教订单贡献统计
|
||
**业务含义**:助教订单流水四项统计,用于精确计算助教的业绩贡献,支持多种分成模式
|
||
|
||
**关键字段**:
|
||
- `contribution_id` (BIGINT): 贡献记录唯一标识(主键)
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `assistant_id` (BIGINT): 助教 ID
|
||
- `order_trade_no` (BIGINT): 订单交易号
|
||
- `member_id` (BIGINT): 会员 ID
|
||
- `stat_date` (DATE): 统计日期(营业日)
|
||
- `contribution_type` (VARCHAR): 贡献类型,如"service_fee"、"table_fee"等
|
||
- `base_amount` (NUMERIC): 基础金额(元)
|
||
- `contribution_amount` (NUMERIC): 贡献金额(元)
|
||
- `contribution_rate` (NUMERIC): 贡献比例(0-1)
|
||
- `calculation_method` (VARCHAR): 计算方法
|
||
- `is_primary_assistant` (BOOLEAN): 是否主要助教
|
||
- `service_duration_minutes` (INTEGER): 服务时长(分钟)
|
||
|
||
#### dws.dws_goods_stock_daily_summary - 商品库存日汇总
|
||
**业务含义**:按日汇总的商品库存变动统计,用于库存分析和补货决策
|
||
|
||
**关键字段**:
|
||
- `site_id` (BIGINT): 门店 ID
|
||
- `site_goods_id` (BIGINT): 门店商品 ID
|
||
- `stat_date` (DATE): 统计日期
|
||
- `goods_name` (TEXT): 商品名称
|
||
- `category_name` (TEXT): 商品分类
|
||
- `opening_stock` (NUMERIC): 期初库存
|
||
- `closing_stock` (NUMERIC): 期末库存
|
||
- `purchase_in` (NUMERIC): 采购入库量
|
||
- `sales_out` (NUMERIC): 销售出库量
|
||
- `transfer_in` (NUMERIC): 调拨入库量
|
||
- `transfer_out` (NUMERIC): 调拨出库量
|
||
- `adjustment_qty` (NUMERIC): 盘点调整量
|
||
- `total_sales_amount` (NUMERIC): 销售总金额(元)
|
||
- `avg_selling_price` (NUMERIC): 平均售价(元)
|
||
- `stock_turnover_days` (NUMERIC): 库存周转天数
|
||
|
||
**查询示例**:
|
||
```sql
|
||
-- 查询库存周转分析
|
||
SELECT
|
||
goods_name,
|
||
category_name,
|
||
AVG(stock_turnover_days) as avg_turnover_days,
|
||
SUM(sales_out) as total_sales_qty,
|
||
SUM(total_sales_amount) as total_sales_amount
|
||
FROM dws_goods_stock_daily_summary
|
||
WHERE site_id = 1001
|
||
AND stat_date >= CURRENT_DATE - INTERVAL '30 days'
|
||
AND sales_out > 0
|
||
GROUP BY goods_name, category_name
|
||
ORDER BY avg_turnover_days ASC;
|
||
```
|
||
|
||
### 指数分析表
|
||
|
||
#### dws.dws_member_spending_power_index - 消费力指数 (SPI)
|
||
**业务含义**:会员消费能力的综合评分,用于精准营销和客户分层
|
||
|
||
**关键字段**:
|
||
- `spi_id` (BIGINT): 记录唯一标识
|
||
- `site_id` (INTEGER): 门店 ID
|
||
- `member_id` (BIGINT): 会员 ID
|
||
- `spend_30` (NUMERIC): 近 30 天消费总额
|
||
- `spend_90` (NUMERIC): 近 90 天消费总额
|
||
- `recharge_90` (NUMERIC): 近 90 天充值总额
|
||
- `orders_30` (INTEGER): 近 30 天消费笔数
|
||
- `orders_90` (INTEGER): 近 90 天消费笔数
|
||
- `visit_days_30` (INTEGER): 近 30 天消费日数
|
||
- `visit_days_90` (INTEGER): 近 90 天消费日数
|
||
- `avg_ticket_90` (NUMERIC): 90 天平均客单价
|
||
- `active_weeks_90` (INTEGER): 近 90 天活跃周数
|
||
- `display_score` (NUMERIC): SPI 展示分(0-10 分)
|
||
- `calc_time` (TIMESTAMPTZ): 计算时间
|
||
|
||
**查询示例**:
|
||
```sql
|
||
-- 查询高价值会员(SPI > 8 分)
|
||
SELECT m.real_name, m.mobile, s.display_score, s.spend_90
|
||
FROM dws_member_spending_power_index s
|
||
JOIN dim_member m ON s.member_id = m.member_id AND s.site_id = m.site_id
|
||
WHERE s.site_id = 1001
|
||
AND s.display_score > 8.0
|
||
AND m.scd2_is_current = 1
|
||
ORDER BY s.display_score DESC;
|
||
```
|
||
|
||
---
|
||
|
||
## 常用查询模式
|
||
|
||
### 1. 会员分析查询
|
||
|
||
```sql
|
||
-- 会员消费趋势分析
|
||
SELECT
|
||
stat_date,
|
||
COUNT(DISTINCT member_id) as active_members,
|
||
SUM(total_amount) as daily_revenue,
|
||
AVG(avg_order_amount) as avg_ticket
|
||
FROM dws_member_daily_summary
|
||
WHERE site_id = 1001
|
||
AND stat_date >= CURRENT_DATE - INTERVAL '30 days'
|
||
GROUP BY stat_date
|
||
ORDER BY stat_date;
|
||
|
||
-- 会员等级分布
|
||
SELECT
|
||
level,
|
||
COUNT(*) as member_count,
|
||
AVG(balance) as avg_balance
|
||
FROM dim_member
|
||
WHERE site_id = 1001
|
||
AND member_status = 1
|
||
AND scd2_is_current = 1
|
||
GROUP BY level
|
||
ORDER BY level;
|
||
```
|
||
|
||
### 2. 助教业绩查询
|
||
|
||
```sql
|
||
-- 助教月度业绩排行
|
||
SELECT
|
||
a.real_name,
|
||
a.nickname,
|
||
SUM(d.service_revenue) as total_revenue,
|
||
SUM(d.service_minutes) as total_minutes,
|
||
AVG(d.avg_rating) as avg_rating
|
||
FROM dws_assistant_daily_detail d
|
||
JOIN dim_assistant a ON d.assistant_id = a.assistant_id
|
||
AND d.site_id = a.site_id
|
||
WHERE d.site_id = 1001
|
||
AND d.stat_date >= DATE_TRUNC('month', CURRENT_DATE)
|
||
AND a.scd2_is_current = 1
|
||
GROUP BY a.assistant_id, a.real_name, a.nickname
|
||
ORDER BY total_revenue DESC;
|
||
```
|
||
|
||
### 3. 经营分析查询
|
||
|
||
```sql
|
||
-- 门店经营概况
|
||
SELECT
|
||
DATE_TRUNC('week', stat_date) as week_start,
|
||
SUM(total_revenue) as weekly_revenue,
|
||
SUM(order_count) as weekly_orders,
|
||
AVG(avg_order_amount) as avg_ticket
|
||
FROM dws_finance_daily_summary
|
||
WHERE site_id = 1001
|
||
AND stat_date >= CURRENT_DATE - INTERVAL '8 weeks'
|
||
GROUP BY DATE_TRUNC('week', stat_date)
|
||
ORDER BY week_start;
|
||
|
||
-- 收入结构分析
|
||
SELECT
|
||
SUM(table_revenue) as table_income,
|
||
SUM(service_revenue) as service_income,
|
||
SUM(goods_revenue) as goods_income,
|
||
SUM(total_revenue) as total_income
|
||
FROM dws_finance_daily_summary
|
||
WHERE site_id = 1001
|
||
AND stat_date >= CURRENT_DATE - INTERVAL '30 days';
|
||
```
|
||
|
||
### 4. 会员行为分析查询
|
||
|
||
```sql
|
||
-- 会员生命周期分析
|
||
SELECT
|
||
CASE
|
||
WHEN s.display_score >= 8.0 THEN '高价值客户'
|
||
WHEN s.display_score >= 6.0 THEN '中价值客户'
|
||
WHEN s.display_score >= 4.0 THEN '普通客户'
|
||
ELSE '低价值客户'
|
||
END as customer_segment,
|
||
COUNT(*) as member_count,
|
||
AVG(s.spend_90) as avg_spend_90d,
|
||
AVG(s.visit_days_90) as avg_active_days,
|
||
AVG(s.avg_ticket_90) as avg_ticket
|
||
FROM dws_member_spending_power_index s
|
||
WHERE s.site_id = 1001
|
||
GROUP BY customer_segment
|
||
ORDER BY AVG(s.display_score) DESC;
|
||
|
||
-- 会员流失风险分析
|
||
SELECT
|
||
m.real_name,
|
||
m.mobile,
|
||
s.spend_90,
|
||
s.visit_days_90,
|
||
s.display_score,
|
||
EXTRACT(days FROM NOW() - MAX(md.stat_date)) as days_since_last_visit
|
||
FROM dws_member_spending_power_index s
|
||
JOIN dim_member m ON s.member_id = m.member_id AND s.site_id = m.site_id
|
||
LEFT JOIN dws_member_daily_summary md ON s.member_id = md.member_id AND s.site_id = md.site_id
|
||
WHERE s.site_id = 1001
|
||
AND s.display_score >= 6.0 -- 高价值客户
|
||
AND m.scd2_is_current = 1
|
||
GROUP BY m.real_name, m.mobile, s.spend_90, s.visit_days_90, s.display_score
|
||
HAVING EXTRACT(days FROM NOW() - MAX(md.stat_date)) > 30 -- 30天未到店
|
||
ORDER BY s.display_score DESC;
|
||
```
|
||
|
||
### 5. 助教绩效分析查询
|
||
|
||
```sql
|
||
-- 助教服务质量分析
|
||
SELECT
|
||
a.real_name,
|
||
a.level_name,
|
||
COUNT(asl.assistant_service_id) as service_count,
|
||
SUM(asl.real_use_seconds)/3600.0 as total_hours,
|
||
AVG(asl.composite_grade) as avg_rating,
|
||
SUM(asl.real_service_money) as total_revenue,
|
||
COUNT(DISTINCT asl.tenant_member_id) as unique_members
|
||
FROM dwd_assistant_service_log asl
|
||
JOIN dim_assistant a ON asl.site_assistant_id = a.assistant_id
|
||
AND asl.site_id = a.site_id
|
||
WHERE asl.site_id = 1001
|
||
AND asl.start_use_time >= CURRENT_DATE - INTERVAL '30 days'
|
||
AND asl.is_trash = 0 -- 排除已废除的服务
|
||
AND a.scd2_is_current = 1
|
||
GROUP BY a.assistant_id, a.real_name, a.level_name
|
||
ORDER BY total_revenue DESC;
|
||
|
||
-- 助教任务完成情况
|
||
SELECT
|
||
a.real_name,
|
||
COUNT(CASE WHEN t.status = 'active' THEN 1 END) as active_tasks,
|
||
COUNT(CASE WHEN t.status = 'completed' THEN 1 END) as completed_tasks,
|
||
COUNT(CASE WHEN t.status = 'abandoned' THEN 1 END) as abandoned_tasks,
|
||
AVG(CASE WHEN t.status = 'completed'
|
||
THEN EXTRACT(days FROM t.completed_at - t.created_at) END) as avg_completion_days
|
||
FROM biz.coach_tasks t
|
||
JOIN dim_assistant a ON t.assistant_id = a.assistant_id AND t.site_id = a.site_id
|
||
WHERE t.site_id = 1001
|
||
AND t.created_at >= CURRENT_DATE - INTERVAL '30 days'
|
||
AND a.scd2_is_current = 1
|
||
GROUP BY a.assistant_id, a.real_name
|
||
ORDER BY completed_tasks DESC;
|
||
```
|
||
|
||
### 6. 库存管理查询
|
||
|
||
```sql
|
||
-- 库存预警分析
|
||
SELECT
|
||
sg.goods_name,
|
||
sg.category_level1_name,
|
||
sg.stock_qty as current_stock,
|
||
sg.safety_stock_qty,
|
||
sg.avg_monthly_sales,
|
||
CASE
|
||
WHEN sg.stock_qty <= sg.safety_stock_qty THEN '库存不足'
|
||
WHEN sg.stock_qty <= sg.safety_stock_qty * 1.5 THEN '库存偏低'
|
||
ELSE '库存正常'
|
||
END as stock_status,
|
||
CASE
|
||
WHEN sg.avg_monthly_sales > 0
|
||
THEN sg.stock_qty / (sg.avg_monthly_sales / 30.0)
|
||
ELSE NULL
|
||
END as estimated_days_remaining
|
||
FROM dim_store_goods sg
|
||
WHERE sg.site_id = 1001
|
||
AND sg.scd2_is_current = 1
|
||
AND sg.not_sale = 0 -- 在售商品
|
||
AND sg.stock_qty <= sg.safety_stock_qty * 2 -- 关注库存偏低的商品
|
||
ORDER BY stock_status, estimated_days_remaining ASC;
|
||
|
||
-- 商品销售趋势分析
|
||
SELECT
|
||
gsm.goods_name,
|
||
gsm.category_name,
|
||
DATE_TRUNC('week', gsm.fetched_at) as week_start,
|
||
AVG(gsm.range_sale) as avg_weekly_sales,
|
||
AVG(gsm.range_sale_money) as avg_weekly_revenue,
|
||
AVG(gsm.current_stock) as avg_stock_level
|
||
FROM dwd_goods_stock_summary gsm
|
||
WHERE gsm.site_id = 1001
|
||
AND gsm.fetched_at >= CURRENT_DATE - INTERVAL '8 weeks'
|
||
AND gsm.range_sale > 0
|
||
GROUP BY gsm.goods_name, gsm.category_name, DATE_TRUNC('week', gsm.fetched_at)
|
||
ORDER BY gsm.goods_name, week_start;
|
||
```
|
||
|
||
### 7. 财务分析查询
|
||
|
||
```sql
|
||
-- 收入结构趋势分析
|
||
SELECT
|
||
stat_date,
|
||
total_revenue,
|
||
table_revenue,
|
||
service_revenue,
|
||
goods_revenue,
|
||
ROUND(table_revenue / NULLIF(total_revenue, 0) * 100, 2) as table_revenue_pct,
|
||
ROUND(service_revenue / NULLIF(total_revenue, 0) * 100, 2) as service_revenue_pct,
|
||
ROUND(goods_revenue / NULLIF(total_revenue, 0) * 100, 2) as goods_revenue_pct
|
||
FROM dws_finance_daily_summary
|
||
WHERE site_id = 1001
|
||
AND stat_date >= CURRENT_DATE - INTERVAL '30 days'
|
||
AND total_revenue > 0
|
||
ORDER BY stat_date DESC;
|
||
|
||
-- 会员充值分析
|
||
SELECT
|
||
DATE_TRUNC('month', ro.pay_time) as month,
|
||
COUNT(*) as recharge_count,
|
||
COUNT(CASE WHEN ro.is_first = 1 THEN 1 END) as first_time_count,
|
||
SUM(ro.pay_amount) as total_recharge_amount,
|
||
AVG(ro.pay_amount) as avg_recharge_amount,
|
||
COUNT(DISTINCT ro.member_id) as unique_members
|
||
FROM dwd_recharge_order ro
|
||
WHERE ro.site_id = 1001
|
||
AND ro.pay_time >= CURRENT_DATE - INTERVAL '12 months'
|
||
GROUP BY DATE_TRUNC('month', ro.pay_time)
|
||
ORDER BY month DESC;
|
||
```
|
||
|
||
### 5. 商品分析查询
|
||
|
||
```sql
|
||
-- 商品销售排行
|
||
SELECT
|
||
g.goods_name,
|
||
g.category_level1_name,
|
||
SUM(s.ledger_count) as total_sold,
|
||
SUM(s.real_goods_money) as total_revenue,
|
||
AVG(s.ledger_unit_price) as avg_price,
|
||
COUNT(DISTINCT s.order_trade_no) as order_count
|
||
FROM dwd_store_goods_sale s
|
||
JOIN dim_store_goods g ON s.site_goods_id = g.site_goods_id
|
||
AND s.site_id = g.site_id
|
||
WHERE s.site_id = 1001
|
||
AND DATE(s.create_time) >= CURRENT_DATE - INTERVAL '30 days'
|
||
AND g.scd2_is_current = 1
|
||
GROUP BY g.site_goods_id, g.goods_name, g.category_level1_name
|
||
ORDER BY total_revenue DESC
|
||
LIMIT 20;
|
||
|
||
-- 库存预警商品
|
||
SELECT
|
||
g.goods_name,
|
||
g.category_level1_name,
|
||
ex.stock_qty as current_stock,
|
||
ex.safety_stock_qty as safety_stock,
|
||
g.avg_monthly_sales,
|
||
CASE
|
||
WHEN ex.stock_qty <= 0 THEN '缺货'
|
||
WHEN ex.stock_qty <= ex.safety_stock_qty THEN '库存预警'
|
||
ELSE '库存正常'
|
||
END as stock_status
|
||
FROM dim_store_goods g
|
||
JOIN dim_store_goods_ex ex ON g.site_goods_id = ex.site_goods_id
|
||
WHERE g.site_id = 1001
|
||
AND g.scd2_is_current = 1
|
||
AND g.goods_state = 1
|
||
AND (ex.stock_qty <= ex.safety_stock_qty OR ex.stock_qty <= 0)
|
||
ORDER BY ex.stock_qty ASC;
|
||
```
|
||
|
||
### 6. 助教业绩深度分析
|
||
|
||
```sql
|
||
-- 助教四项统计分析(基于订单贡献表)
|
||
SELECT
|
||
a.real_name,
|
||
a.nickname,
|
||
COUNT(*) as stat_days,
|
||
SUM(c.order_count) as total_orders,
|
||
SUM(c.total_service_seconds)/3600.0 as total_service_hours,
|
||
AVG(c.order_gross_revenue) as avg_gross_revenue,
|
||
AVG(c.order_net_revenue) as avg_net_revenue,
|
||
AVG(c.time_weighted_revenue) as avg_time_weighted_revenue,
|
||
AVG(c.time_weighted_net_revenue) as avg_time_weighted_net_revenue
|
||
FROM dws_assistant_order_contribution c
|
||
JOIN dim_assistant a ON c.assistant_id = a.assistant_id
|
||
AND c.site_id = a.site_id
|
||
WHERE c.site_id = 1001
|
||
AND c.stat_date >= CURRENT_DATE - INTERVAL '30 days'
|
||
AND a.scd2_is_current = 1
|
||
GROUP BY a.assistant_id, a.real_name, a.nickname
|
||
ORDER BY AVG(c.time_weighted_net_revenue) DESC;
|
||
```
|
||
AND m.scd2_is_current = 1
|
||
ORDER BY s.display_score DESC, s.spend_90 DESC;
|
||
```
|
||
|
||
---
|
||
|
||
## 安全与限制
|
||
|
||
### 访问控制
|
||
- **只读权限**:仅允许 SELECT、WITH、SHOW、EXPLAIN 操作
|
||
- **Schema 隔离**:查询自动限制在指定 schema 内,禁止跨 schema 引用
|
||
- **行数限制**:单次查询最多返回 500 行数据(可配置)
|
||
- **Token 鉴权**:支持可选的 Bearer Token 认证
|
||
|
||
### 数据安全
|
||
- **敏感信息**:手机号、身份证等敏感字段已脱敏处理
|
||
- **多门店隔离**:通过 `site_id` 实现数据隔离,防止跨门店数据泄露
|
||
- **审计日志**:所有查询操作都有完整的访问日志记录
|
||
|
||
### 性能优化
|
||
- **索引优化**:关键查询字段都建立了合适的索引
|
||
- **物化视图**:常用汇总查询使用物化视图加速
|
||
- **连接池**:使用连接池管理数据库连接,提高并发性能
|
||
|
||
---
|
||
|
||
## 故障排查
|
||
|
||
### 常见错误
|
||
|
||
1. **Schema 不存在**
|
||
- 错误:`存在不允许的 schema`
|
||
- 解决:检查 schema 名称是否正确,仅支持 `ods`/`dwd`/`dws`/`core`/`meta`/`app`
|
||
|
||
2. **SQL 被拒绝**
|
||
- 错误:`SQL 被拒绝:仅允许只读`
|
||
- 解决:检查 SQL 语句,确保只使用 SELECT、WITH、SHOW、EXPLAIN
|
||
|
||
3. **跨 Schema 引用**
|
||
- 错误:`检测到跨 schema 引用`
|
||
- 解决:在单个 schema 内查询,或使用 `describe_schemas` 获取多 schema 信息
|
||
|
||
4. **连接超时**
|
||
- 错误:连接数据库失败
|
||
- 解决:检查网络连接和数据库服务状态
|
||
|
||
### 调试建议
|
||
|
||
1. **先探索后查询**:使用 `list_tables` 和 `describe_table` 了解数据结构
|
||
2. **小范围测试**:先用 LIMIT 限制返回行数,确认查询正确后再扩大范围
|
||
3. **关注时间范围**:大部分汇总表按营业日归属,注意时间筛选条件
|
||
4. **利用索引**:查询时尽量使用 `site_id`、`stat_date` 等索引字段
|
||
|
||
---
|
||
|
||
## 配置说明
|
||
|
||
### 环境变量
|
||
|
||
| 变量名 | 说明 | 默认值 |
|
||
|--------|------|--------|
|
||
| `MCP_PG_HOST` | 数据库主机地址 | 回退到 `DB_HOST` |
|
||
| `MCP_PG_PORT` | 数据库端口 | 回退到 `DB_PORT`,默认 5432 |
|
||
| `MCP_PG_DATABASE` | 数据库名 | 回退到 `ETL_DB_NAME` |
|
||
| `MCP_PG_USER` | 数据库用户 | 回退到 `DB_USER` |
|
||
| `MCP_PG_PASSWORD` | 数据库密码 | 回退到 `DB_PASSWORD` |
|
||
| `MCP_TOKEN` | API 鉴权 Token | 空(不启用鉴权) |
|
||
| `MCP_MAX_ROWS` | 最大返回行数 | 500 |
|
||
| `PORT` | 服务监听端口 | 9000 |
|
||
|
||
### 启动服务
|
||
|
||
```bash
|
||
cd apps/mcp-server
|
||
python server.py
|
||
```
|
||
|
||
服务启动后,MCP 端点地址为:`http://localhost:9000/mcp`
|
||
|
||
---
|
||
|
||
## 最佳实践
|
||
|
||
### 1. 数据探索流程
|
||
1. 使用 `list_tables` 了解可用表
|
||
2. 使用 `describe_table` 查看表结构
|
||
3. 使用 `query_sql` 执行小范围测试查询
|
||
4. 逐步扩大查询范围和复杂度
|
||
|
||
### 2. 查询优化建议
|
||
- 总是在 WHERE 条件中包含 `site_id` 进行门店过滤
|
||
- 使用日期范围限制大表查询,避免全表扫描
|
||
- 优先使用 DWS 层的汇总表,避免实时聚合计算
|
||
- 合理使用 LIMIT 限制返回数据量
|
||
|
||
### 3. 业务理解要点
|
||
- **营业日概念**:08:00 为分界点,之前归属前一天,使用 `dws.biz_date()` 函数计算
|
||
- **金额精度**:所有金额字段精确到分(NUMERIC(18,2)),货币单位为人民币(CNY)
|
||
- **会员状态**:注意区分 `member_status`(账户状态)和 `scd2_is_current`(版本状态)
|
||
- **助教服务**:区分服务类型(陪打/促销)和计费方式,关注评分和时长,注意废除状态
|
||
- **多门店隔离**:所有查询都应包含 `site_id` 过滤条件,实现门店级数据隔离
|
||
- **SCD2 维度**:维度表查询时需要 `scd2_is_current = 1` 获取当前版本
|
||
- **库存管理**:区分当前库存、批次库存、安全库存,关注库存变动类型
|
||
- **任务系统**:助教任务有生命周期状态,支持置顶、过期、放弃等操作
|
||
- **备注分类**:统一备注表通过 type 字段区分不同业务场景的备注
|
||
- **触发器调度**:支持 cron、interval、event 三种触发方式的自动化任务
|
||
|
||
### 数据质量注意事项
|
||
- **时间字段**:注意区分创建时间、更新时间、业务发生时间
|
||
- **外键关联**:跨表查询时注意 `site_id` 的一致性约束
|
||
- **软删除**:部分表使用 `is_delete` 字段标记软删除,查询时需要过滤
|
||
- **枚举值**:状态字段使用整数枚举,需要了解具体含义
|
||
- **NULL 处理**:可选字段可能为 NULL,聚合计算时需要适当处理
|
||
- **精度问题**:时长字段有的用秒,有的用分钟,注意单位转换
|
||
|
||
通过本手册,AI 应用可以高效、安全地访问台球门店的运营数据,为智能分析和决策提供强有力的数据支撑。手册涵盖了从基础的表结构查询到复杂的业务分析,为各种数据需求提供了完整的解决方案。 |