Files
Neo-ZQYY/docs/mcp/AI-DATABASE-QUERY-MANUAL.md

44 KiB
Raw Permalink Blame History

MCP AI 查库手册

项目地址apps/mcp-server
目标用户AI 应用(阿里云百炼)通过 MCP 协议查询 PostgreSQL 数据库
数据库etl_feiqiuETL 数据仓库,六层架构)
服务地址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): 是否包含视图

返回示例

{
  "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

返回示例

{
  "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 最大返回表数量

返回示例

{
  "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

返回示例

{
  "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=历史

查询示例

-- 查询某门店的活跃会员
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): 备注说明

查询示例

-- 查询某会员的余额变动历史
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): 消费会员 ID0 表示散客
  • 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): 实付金额

查询示例

-- 查询某门店今日订单统计
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): 所属团队 ID0 表示未分组
  • 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): 当前关联的订单 ID0表示空闲
  • 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): 台灯熄灭延迟时间(秒)

查询示例

-- 查询某门店的台桌使用情况
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): 备注说明,如"结账退货"、"采购退货"、"系统自动领用"

查询示例

-- 查询某商品的库存变动历史
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

查询示例

-- 查询助教的活跃任务
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. 时效净贡献:扣除个人分成后的净贡献,最终的业绩指标

查询示例

-- 助教业绩四项统计对比
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'

查询示例

-- 商品库存变动分析
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): 库存周转天数

查询示例

-- 查询库存周转分析
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): 计算时间

查询示例

-- 查询高价值会员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. 会员分析查询

-- 会员消费趋势分析
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. 助教业绩查询

-- 助教月度业绩排行
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. 经营分析查询

-- 门店经营概况
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. 会员行为分析查询

-- 会员生命周期分析
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. 助教绩效分析查询

-- 助教服务质量分析
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. 库存管理查询

-- 库存预警分析
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. 财务分析查询

-- 收入结构趋势分析
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. 商品分析查询

-- 商品销售排行
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. 助教业绩深度分析

-- 助教四项统计分析(基于订单贡献表)
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 应用可以高效、安全地访问台球门店的运营数据,为智能分析和决策提供强有力的数据支撑。手册涵盖了从基础的表结构查询到复杂的业务分析,为各种数据需求提供了完整的解决方案。