first commit

This commit is contained in:
陈辅元
2026-04-10 16:52:07 +08:00
commit 84fe545640
87 changed files with 20842 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
# Text2SQL Agent 环境配置示例
# 复制为 .env 并填入实际值
# ========== DeepSeek API 配置 ==========
DEEPSEEK_API_KEY=sk-2e3cc9f79a2c40e9a6b7c960d8c090d9
DEEPSEEK_BASE_URL=https://api.deepseek.com
# 模型配置
# 主生成模型
MODEL_PRIMARY=deepseek-reasoner
TEMPERATURE=0 # 确定性模式:每次生成相同结果
MAX_TOKENS=4096
# 生成与校验默认 SQL Server(T-SQL);可改为 mysql / postgresql 等
TEXT2SQL_DIALECT=sqlserver
# ========== Embedding 配置 ==========
# false = 使用兼容 OpenAI 的远程 /v1/embeddings(优先 ModelScope,未配置 MODELSCOPE_* 时用 DashScope)
USE_LOCAL_EMBEDDING=false
# ModelScope 推理 API:https://www.modelscope.cn/docs/inference-api
# MODELSCOPE_API_KEY=ms-b95f3233-4797-4efd-90e6-b3728743571d
# MODELSCOPE_BASE_URL=https://api-inference.modelscope.cn/v1
# MODELSCOPE_EMBEDDING_MODEL=Qwen/Qwen3-Embedding-8B
# # 单次请求最大条数,按服务端限制调整
# MODELSCOPE_EMBEDDING_MAX_BATCH=32
# 兼容 OpenAI 的网关:地址含 /v1(若网关根路径即 OpenAI API 则按实际填写)
OPENAI_BASE_URL=http://113.192.49.54:9080/v1
OPENAI_API_KEY=sk-proj-FEb2ChHZK5Llm0tBkmNIT3BlbkFJbu0b0zQpTW8762yD6HDv
OPENAI_EMBEDDING_MODEL=text-embedding-ada-002
# ========== Schema 配置 ==========
SCHEMA_DIR=./data/schemas
SCHEMA_FILE=${SCHEMA_DIR}/G3SB_MCDataDictionary_table_structure.json
# ========== 向量数据库配置 ==========
VECTOR_DB_PATH=./data/embeddings/chroma
# ========== 验证配置 ==========
ENABLE_SQL_VALIDATION=true
BLOCK_DANGEROUS_SQL=true
# ========== 重试配置 ==========
MAX_RETRY=1 # 确定性模式:只尝试一次,不重试
RETRY_DELAY=1.0
# ========== Few-shot 配置 ==========
# 是否启用经验数据集few-shot增强
FEWSHOT_ENABLED=true
# 每次使用的示例数量
FEWSHOT_TOP_K=3
# 示例最低评分(1-10)
FEWSHOT_MIN_RATING=7
# 经验数据集路径
FEWSHOT_DATA_PATH=./data/experiences/all_samples.jsonl
# ========== 日志配置 ==========
LOG_LEVEL=INFO
LOG_FILE=./logs/text2sql.log
+736
View File
@@ -0,0 +1,736 @@
# Text2SQL 多智能体系统
基于 **CAMEL AI 框架**、**DeepSeek 大模型** 和 **经验数据集 Few-Shot 增强** 的专业 Text-to-SQL 生成系统,专为证券经纪业务领域优化。
## 🚀 核心特性
- **🤖 多Agent协作流水线**:Schema Linker → SQL Generator → Validator 三阶段协作
- **🎯 高精度表检索**:向量检索(Qwen3-Embedding)+ LLM精筛,从 250+ 张表中精准定位相关表
- **💡 经验数据集 Few-Shot**:基于 50 条高质量样例的语义检索,动态注入相似示例提升准确率
- **🔒 双重验证机制**:程序语法验证 + LLM语义验证,确保 SQL 正确性
- **🏦 金融领域深度优化**:针对证券经纪业务(账户、持仓、现金、结算)定制 Prompt 和推断规则
- **✍️ 确定性模式**:Temperature=0 + 单次重试,保证相同输入产生稳定输出
- **🌐 多方言支持**:T-SQL(SQL Server)/ MySQL / PostgreSQL / SQLite
- **🔄 自修正循环**:验证失败自动重试(最多 2 次),智能修正 SQL
## 📊 系统架构
```
┌─────────────────────────────────────────────────────────────────┐
│ 用户自然语言问题 │
└────────────────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 阶段1: Schema Linker Agent │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 1.1 向量检索粗筛(ChromaDB + Qwen3-Embedding) │ │
│ │ - 检索 Top 20 候选表(相似度阈值 0.1) │ │
│ │ └─ 支持对手方/经纪商问题特殊处理(强制纳入 Broker 表) │ │
│ │ │ │
│ │ 1.2 LLM 精筛 │ │
│ │ - 基于表注释选择最多 5 张相关表 │ │
│ │ └─ 输出:relevant_tables + reasoning(JSON格式) │ │
│ │ │ │
│ │ 1.3 外键扩展 │ │
│ │ - 自动添加被引用表(FK → ref_table) │ │
│ │ - 自动添加引用表(反向外键,确保 LEFT JOIN 完整性) │ │
│ └───────────────────────────────────────────────────────────┘ │
│ ↓ 精简 Schema 子集 │
└────────────────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 阶段2: SQL Generator Agent(集成 Few-Shot 增强) │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 2.1 语义检索相似示例 │ │
│ │ - 从 50 条经验数据集中检索 Top-K 高评分示例 │ │
│ │ - 支持语义匹配(SentenceTransformer)或关键词回退 │ │
│ │ │ │
│ │ 2.2 注入 Prompt │ │
│ │ "参考以下相似示例的SQL编写风格:<examples>" │ │
│ │ │ │
│ │ 2.3 生成 T-SQL │ │
│ │ - 遵循标准版式(SELECT 每列一行、4 空格缩进) │ │
│ │ - 正确使用方括号 [TableName]、[ColumnName] │ │
│ │ - 日期函数:CAST(GETDATE() AS DATE)、DATEADD │ │
│ │ - 字符串连接:+ 运算符 │ │
│ └───────────────────────────────────────────────────────────┘ │
│ ↓ SQL 语句 │
└────────────────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 阶段3: Validator Agent │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 3.1 程序验证(确定性规则) │ │
│ │ ✓ SQL 语法正确(sqlglot 解析) │ │
│ │ ✓ Schema 一致性(表/字段存在性) │ │
│ │ ✓ 别名解析正确(JOIN 别名匹配) │ │
│ │ ✓ 无危险操作(DROP/DELETE/UPDATE 等拦截) │ │
│ │ │ │
│ │ 3.2 LLM 语义验证 │ │
│ │ ✓ 业务逻辑合理性 │ │
│ │ ✓ 聚合函数使用正确(COUNT/SUM/AVG 等) │ │
│ │ ✓ WHERE 条件无矛盾 │ │
│ │ │ │
│ │ 3.3 结果判断 │ │
│ │ ✅ 通过 → 返回最终 SQL │ │
│ │ ❌ 失败 → 重试(最多 MAX_RETRY 次) │ │
│ └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
## 🛠️ 技术栈
| 组件 | 技术选型 | 版本/说明 |
|------|---------|-----------|
| Agent 框架 | **CAMEL AI** | >= 0.2.0,角色扮演、消息通信 |
| LLM 模型 | **DeepSeek-chat** | 国产大模型,代码生成能力强 |
| Embedding | **Qwen3-Embedding-0.6B** | 阿里云 6 亿参数,本地免费部署 |
| 向量数据库 | **ChromaDB** | 本地轻量,持久化 Schema 索引 |
| SQL 解析 | **sqlglot** | >= 20.0.0,多方言 AST 转换与验证 |
| 配置管理 | **Pydantic Settings** | 类型安全的环境变量管理 |
| 数据处理 | **pandas / numpy** | 结构化数据操作 |
## 📁 项目结构
```
text2sql_agent_camel/
├── agents/ # Agent 层
│ ├── orchestrator.py # 主编排器(协调 Schema Linker → Generator → Validator)
│ ├── schema_linker.py # 表筛选 Agent(粗筛 + LLM 精筛 + 外键扩展)
│ ├── sql_generator.py # SQL 生成 Agent(集成 Few-Shot 注入)
│ └── validator.py # SQL 验证 Agent(程序 + LLM 双重验证)
├── config/
│ ├── prompts.py # 系统与用户 Prompt 模板
│ └── settings.py # 配置类(基于 Pydantic)
├── schema/ # Schema 管理层
│ ├── models.py # 数据模型(Table, Column, ForeignKey, DatabaseSchema)
│ ├── loader.py # Schema 加载器(JSON / G3SB 格式解析)
│ ├── manager.py # Schema 管理器(查询、过滤、转字符串)
│ └── indexer.py # 向量索引构建器(ChromaDB 封装)
├── llm/
│ └── deepseek_client.py # DeepSeek API 客户端(chat / validate_sql / select_tables)
├── utils/
│ ├── embedding.py # Qwen3-Embedding 封装(本地 / 远程 API)
│ ├── sql_parser.py # sqlglot 工具(语法验证、方言转换、规范化)
│ ├── validators.py # 验证逻辑(危险操作检测、完整验证流水线)
│ └── fewshot_selector.py # Few-Shot 示例选择器(语义/关键词检索)
├── data/
│ ├── schemas/ # Schema JSON 文件
│ │ ├── G3SB_MCDataDictionary_table_structure.json # 表结构
│ │ └── G3SB_MCDataDictionary_table_meta.json # 表注释元数据
│ ├── experiences/ # 经验数据集(Few-Shot 数据源)
│ │ ├── all_samples.jsonl # 50 条样本(全部)
│ │ ├── high_rating_samples.jsonl # 30 条高质量样本(rating ≥ 8)
│ │ ├── difficulty_easy.jsonl / medium.jsonl / hard.jsonl
│ │ ├── fewshot_examples.md # Markdown 格式示例
│ │ └── by_tag/ # 按标签分类(20 类)
│ ├── embeddings/ # ChromaDB 向量索引持久化目录
│ └── models/ # 本地 Embedding 模型权重
├── scripts/
│ ├── parse_examples.py # 解析 Example_text2sql.md → 结构化数据集
│ ├── integrate_fewshot.py # Few-Shot 集成指南与测试
│ └── patch_fewshot.py # 自动化修改 orchestrator.py(已内置)
├── logs/
│ └── text2sql.log # 运行日志(默认)
├── .env # 环境变量配置(API Key、路径、参数)
├── main.py # CLI 入口(单次查询 / 批量 / 交互模式)
├── pyproject.toml # 项目元数据与依赖
├── README.md # 本文档
└── SQL_GENERATION_LOGIC.md # SQL 生成逻辑详解(流程图、示例)
```
## ⚡ 快速开始
### 前置要求
- Python **3.10+**
- DeepSeek API Key(申请地址:https://platform.deepseek.com/api_keys)
- (可选)本地 Embedding 模型权重(或配置远程 Embedding API)
### 1. 安装依赖
```bash
# 使用 uv(推荐,速度快)
uv pip install -e .
# 或使用 pip
pip install -r requirements.txt
```
依赖清单(pyproject.toml):
```toml
dependencies = [
"camel-ai>=0.2.0",
"openai>=1.0.0",
"chromadb>=0.4.0",
"transformers>=4.36.0",
"torch>=2.0.0",
"sqlglot>=20.0.0",
"pydantic>=2.0.0",
"sentence-transformers>=2.2.0", # Few-Shot 语义检索
"python-dotenv>=1.0.0",
]
```
### 2. 配置环境变量
```bash
# 复制模板并编辑
cp .env .env.local # 或直接编辑 .env
# 必填项
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
DEEPSEEK_BASE_URL=https://api.deepseek.com
# 可选:使用本地 Embedding(无需网络,但需下载模型)
USE_LOCAL_EMBEDDING=true
EMBEDDING_MODEL_PATH=./data/models/Qwen3-Embedding-0.6B
# 或使用远程 Embedding API(无需本地模型)
USE_LOCAL_EMBEDDING=false
MODELSCOPE_API_KEY=ms-xxxxxxxx
MODELSCOPE_BASE_URL=https://api-inference.modelscope.cn/v1
MODELSCOPE_EMBEDDING_MODEL=Qwen/Qwen3-Embedding-8B
```
### 3. 准备 Schema 文件
将 G3SB 系统的 Schema 导出为 JSON 格式,并放置到 `data/schemas/` 目录:
```bash
# 目录结构
data/schemas/
├── G3SB_MCDataDictionary_table_structure.json # 必需:表结构定义
└── G3SB_MCDataDictionary_table_meta.json # 可选:表注释(用于 LLM 理解)
```
Schema JSON 格式示例:
```json
{
"database": "G3SB_MC",
"tables": [
{
"name": "MCAccount",
"comment": "账户主表",
"columns": [
{"name": "AccountID", "type": "NCHAR(16)", "comment": "账户唯一标识", "nullable": false, "primary_key": true},
{"name": "AccountName", "type": "NVARCHAR(100)", "comment": "账户名称"},
{"name": "State", "type": "CHAR(1)", "comment": "状态: A=Active, D=Deleted, X=SameDayDeleted"},
{"name": "OpenDate", "type": "DATE", "comment": "开户日期"}
],
"foreign_keys": [
{"columns": ["AEID"], "ref_table": "MCUser", "ref_columns": ["UserID"]}
]
}
]
}
```
### 4. 构建向量索引(首次运行)
```bash
# 自动构建:首次查询时会自动创建
python main.py "测试查询"
# 或手动预构建(推荐,加速首次查询)
python -c "
from agents.orchestrator import Text2SQLOrchestrator
from schema.manager import SchemaManager
schema = SchemaManager.load_from_json('./data/schemas/G3SB_MCDataDictionary_table_structure.json')
orch = Text2SQLOrchestrator(schema_mgr=schema, deepseek_api_key='sk-xxx')
orch.build_vector_index(force_rebuild=True)
"
```
### 5. 运行演示
```bash
# 单次查询(默认 T-SQL / SQL Server)
python main.py "查询2024年1月的销售额"
# 交互模式
python main.py --interactive
# 批量查询(每行一个问题)
python main.py --batch queries.txt
# 指定 Schema 和方言
python main.py "统计每个市场的未结算交易量" \
--schema ./data/schemas/custom_schema.json \
--dialect postgresql
# 禁用 Few-Shot(对比实验)
python main.py "查询活跃账户数" --no-fewshot
# 调整 Few-Shot 参数
python main.py "查询2024年1月的销售额" \
--fewshot-top-k 5 \
--fewshot-min-rating 8
# 详细日志(调试用)
python main.py "查询持仓余额" --verbose
```
## 🎯 使用示例
### Python API
```python
import os
from agents.orchestrator import Text2SQLOrchestrator
from schema.manager import SchemaManager
from llm.deepseek_client import DeepSeekConfig
# 1. 加载 Schema
schema_mgr = SchemaManager.load_from_json(
"./data/schemas/G3SB_MCDataDictionary_table_structure.json",
g3sb_meta_path="./data/schemas/G3SB_MCDataDictionary_table_meta.json"
)
# 2. 配置 DeepSeek
config = DeepSeekConfig(
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url=os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com"),
model_name="deepseek-chat",
temperature=0, # 确定性模式
max_tokens=4096,
)
# 3. 初始化编排器
orchestrator = Text2SQLOrchestrator(
schema_manager=schema_mgr,
deepseek_config=config,
max_retry=1, # 单次尝试(确定性)
use_vector_search=True, # 启用向量检索
fewshot_enabled=True, # 启用 Few-Shot
fewshot_top_k=3, # 每次使用 3 个示例
fewshot_min_rating=7, # 最低评分过滤
)
# 4. 生成 SQL
result = orchestrator.generate(
question="查询2024年1月的销售额最高的前10个产品",
dialect="tsql",
top_k_candidates=20
)
# 5. 查看结果
print(f"SQL: {result.sql}")
print(f"有效: {result.valid}")
print(f"使用表: {result.tables_used}")
print(f"尝试次数: {result.attempts}")
print(f"推理过程: {result.reasoning}")
if result.warnings:
print(f"警告: {result.warnings}")
```
### 典型查询与期望输出
| 用户问题 | 生成 SQL(T-SQL) | 关键特性 |
|---------|------------------|---------|
| "查询2024年1月的销售额" | `WHERE TradeDate >= '2024-01-01' AND TradeDate < '2024-02-01'` | 日期范围推断 |
| "统计所有活跃账户数" | `WHERE State = 'A'` | 状态值推断 |
| "查询每个对手方的未结算交易总额" | `LEFT JOIN MCBroker ... GROUP BY ... ORDER BY SUM(...) DESC` | 多表 JOIN + 聚合 + 排序 |
| "列出今天的所有 Margin Call" | `WHERE TradeDate >= CAST(GETDATE() AS DATE)` | 相对日期处理 |
| "查询账户 ACC001 的持仓" | `WHERE AccountID = 'ACC001'` | 精确匹配 |
## 🔧 核心配置
### 环境变量(`.env`)
```ini
# ========== DeepSeek API ==========
DEEPSEEK_API_KEY=sk-xxxxxxxx
DEEPSEEK_BASE_URL=https://api.deepseek.com
# ========== 模型参数 ==========
TEMPERATURE=0 # 0=确定性,0.3=推荐平衡值
MAX_TOKENS=4096
TEXT2SQL_DIALECT=tsql # tsql / mysql / postgresql / sqlite
# ========== 检索配置 ==========
MAX_RETRY=1 # 重试次数(1=仅首次,2=允许一次修正)
FEWSHOT_ENABLED=true # 是否启用 Few-Shot
FEWSHOT_TOP_K=3 # 每次注入的示例数量
FEWSHOT_MIN_RATING=7 # 示例最低评分(1-10)
# ========== Embedding ==========
USE_LOCAL_EMBEDDING=false # true=本地模型,false=远程API
# 本地模型路径
EMBEDDING_MODEL_PATH=./data/models/Qwen3-Embedding-0.6B
# 远程 API(ModelScope)
MODELSCOPE_API_KEY=ms-xxxx
MODELSCOPE_BASE_URL=https://api-inference.modelscope.cn/v1
MODELSCOPE_EMBEDDING_MODEL=Qwen/Qwen3-Embedding-8B
# ========== Schema ==========
SCHEMA_DIR=./data/schemas
SCHEMA_FILE=${SCHEMA_DIR}/G3SB_MCDataDictionary_table_structure.json
# ========== 向量数据库 ==========
VECTOR_DB_PATH=./data/embeddings/chroma
```
### CLI 参数速查
```bash
python main.py [问题] [选项]
# 核心选项
--schema PATH Schema 文件路径
--dialect {mysql,postgresql,sqlite,tsql} 目标 SQL 方言
--api-key KEY DeepSeek API Key(优先于环境变量)
# 生成控制
--temperature FLOAT 采样温度(0-1,默认 0.3)
--max-tokens INT LLM 最大输出 token(默认 4096)
--max-retry INT 最大重试次数(默认 2)
# Few-Shot
--no-fewshot 禁用经验数据集增强
--fewshot-top-k N 每次使用的示例数量(默认 3)
--fewshot-min-rating N 示例最低评分(默认 7)
# 向量检索
--no-vector-search 禁用向量检索(使用全部表)
--embedding-model PATH Embedding 模型路径
# 其他
--interactive, -i 交互模式
--batch FILE 批量文件路径
--verbose, -v 详细日志
```
## 📈 性能与调优
### 影响因素与优化策略
| 维度 | 影响因素 | 优化建议 |
|------|---------|---------|
| **召回率** | 向量阈值 `score_threshold=0.1` | 降低至 0.05 可提高召回,但可能引入噪声 |
| **准确率** | Few-Shot 示例质量 | 补充更多高评分(≥8)样本,按业务域分类 |
| **响应速度** | 候选表数 `top_k_candidates=20` | 减少至 10-15,牺牲召回保速度 |
| **成本** | 重试次数 `max_retry` | 确定性模式下设为 1,避免重复调用 |
| **稳定性** | `TEMPERATURE` | 生产环境设为 0,确保结果可重现 |
### 典型性能数据(实测参考)
| 查询类型 | 表数 | 响应时间 | 准确率 |
|---------|------|---------|-------|
| 单表简单查询 | 1-2 | 8-12s | >90% |
| 2-3 表 JOIN | 2-3 | 12-18s | >85% |
| 聚合 + GROUP BY | 1-2 | 15-22s | >80% |
| 复杂多表(4+) | 4-6 | 25-35s | >70% |
*注:时间包含向量检索(~2s)+ LLM 生成(~5-10s)+ 验证(~1-3s),网络条件不同可能有差异。*
## 🧪 测试
```bash
# 安装测试依赖
pip install pytest pytest-cov
# 运行单元测试
pytest tests/unit/ -v
# 运行集成测试
pytest tests/integration/ -v --tb=short
# 覆盖率报告
pytest --cov=agents --cov=utils --cov-report=html
```
测试数据集:`data/Example/Example_text2sql.md` 中的 50 个标注样本。
## 📚 经验数据集(Few-Shot 数据源)
### 数据来源
`data/Example/Example_text2sql.md` — 领域专家标注的 50 个 Q&A 对,包含:
- 中英双语问题
- 专家级 T-SQL 实现
- SQL 编写理由(explanation)
- 人工评分(1-10 分,平均 7.6 分)
- 业务标签(filter, join, aggregation, broker, account...)
- 难度等级(easy / medium / hard)
### 生成数据集
```bash
# 解析 MD 文件,生成结构化数据
python scripts/parse_examples.py
# 输出文件
data/experiences/
├── all_samples.jsonl # 50 条完整样本
├── high_rating_samples.jsonl # 30 条高质量样本(rating ≥ 8)
├── difficulty_easy.jsonl # 27 条简单问题
├── difficulty_medium.jsonl # 6 条中等问题
├── difficulty_hard.jsonl # 17 条复杂问题
├── fewshot_examples.md # Markdown 格式,便于阅读
└── by_tag/ # 按标签分类(20 个目录)
├── filter.jsonl
├── join.jsonl
├── aggregation.jsonl
└── ...
```
### Few-Shot 检索逻辑
1. **语义匹配优先**:使用 SentenceTransformer 计算问题相似度(需下载模型)
2. **关键词回退**:无模型时使用中文 2-gram + 英文 token 匹配
3. **过滤条件**:
- `min_rating`:示例评分 ≥ 阈值
- `max_difficulty`:示例难度不超过指定等级
- `required_tags`:必须包含的标签(可选)
4. **排序**:相似度降序,返回 Top-K
## 🏦 领域知识:证券经纪业务(G3SB 系统)
### 数据库概览
| 模块 | 表前缀 | 说明 | 表数 |
|------|-------|------|------|
| Master Client | `MC*` | 客户、账户、产品主数据 | ~80 |
| Broker Cash | `BC*` | 资金余额、日终结算 | ~40 |
| History Cash | `HC*` | 资金历史流水(时序) | ~60 |
| Hong Kong Stock | `HXSB*` | 港股业务 | ~30 |
| Vietnam Market | `HCVSD*` | 越南市场 | ~15 |
| Reporting | `VSB*`, `VSBRpt*` | 报表视图(预计算) | ~120+ |
### 关键字段约定
| 字段名 | 类型 | 说明 | 示例值 |
|--------|------|------|--------|
| `AccountID` | NCHAR(16) | 账户唯一标识 | `'ACC0001234567'` |
| `MarketID` | NCHAR(4) | 市场代码 | `'HK'` / `'VN'` / `'CN'` |
| `InstrumentID` | NCHAR(16) | 证券代码 | `'00700.HK'` |
| `CurrencyID` | NCHAR(3) | 币种 | `'USD'` / `'HKD'` / `'CNY'` |
| `ValueDate` | DATE | 价值日期(结算日) | `'2024-01-15'` |
| `TradeDate` | DATE | 交易日期 | `'2024-01-14'` |
| `BusinessDate` | DATE | 业务日期(当前处理日) | `'2024-01-15'` |
| `Settled` | DECIMAL | 已结算余额 | `123456.78` |
| `State` | CHAR(1) | 记录状态 | `A`=活跃, `D`=已删除, `X`=当日删除 |
| `SettleStatus` | CHAR(1) | 结算状态 | `U`=未结算, `S`=已结算 |
### 常见业务查询模式
```sql
-- 1. 查询未结算交易(按对手方分组)
SELECT
b.BrokerID,
m.Name AS BrokerName,
COUNT(*) AS UnsettledTradeCount,
SUM(b.SettleAmount) AS TotalUnsettledAmount
FROM TSBBrokerContract b
LEFT JOIN MCBroker m ON b.BrokerID = m.BrokerID
WHERE b.SettleStatus = 'U' -- 未结算
AND b.CashSettleDate <= CAST(GETDATE() AS DATE) -- 截至今日
GROUP BY b.BrokerID, m.Name
ORDER BY TotalUnsettledAmount DESC;
-- 2. 查询账户资金(多币种)
SELECT
AccountID,
CurrencyID,
SUM(CASE WHEN Settled > 0 THEN Settled ELSE 0 END) AS CreditBalance,
SUM(CASE WHEN Settled < 0 THEN Settled ELSE 0 END) AS DebitBalance
FROM BCAccountCash
WHERE AccountID = 'ACC001'
GROUP BY AccountID, CurrencyID;
-- 3. 查询持仓(包含产品名称)
SELECT
i.InstrumentID,
p.InstrumentName,
i.Settled AS Quantity,
i.MarketPrice AS UnitPrice,
i.Settled * i.MarketPrice AS MarketValue
FROM MCAccountInstrument i
LEFT JOIN MCProduct p ON i.InstrumentID = p.InstrumentID
WHERE i.AccountID = 'ACC001'
AND i.Settled <> 0;
```
## 🔍 问题排查
### 1. 向量索引为空 / 检索不准
**现象**:`schema.indexer: 索引为空,正在构建...` 每次都重建,或返回表不相关。
**排查**:
```bash
# 检查索引文件
ls -la data/embeddings/chroma/
# 强制重建索引
python -c "
from agents.orchestrator import Text2SQLOrchestrator
from schema.manager import SchemaManager
s = SchemaManager.load_from_json('./data/schemas/...json')
orch = Text2SQLOrchestrator(schema_mgr=s, deepseek_api_key='sk-xxx')
orch.build_vector_index(force_rebuild=True)
"
```
**原因**:Embedding 模型未加载成功,或 ChromaDB 文件损坏。
---
### 2. Few-Shot 未生效
**现象**:日志中未见 "已注入 X 个 few-shot 示例"。
**排查**:
```bash
# 检查数据文件
python -c "
from utils.fewshot_selector import FewShotSelector
s = FewShotSelector('./data/experiences/all_samples.jsonl')
print(f'样本数: {len(s.samples)}')
ex = s.select('查询账户余额', top_k=3, min_rating=7)
print(f'选中: {[e.qid for e in ex]}')
"
```
**常见原因**:
- 文件路径错误 → 检查 `FEWSHOT_DATA_PATH`
- 评分过滤过高 → 降低 `FEWSHOT_MIN_RATING`
- 语义匹配未加载模型 → 检查网络或使用本地模型
---
### 3. 生成 SQL 字段错误
**现象**:SQL 语法正确,但字段名与 Schema 不匹配。
**原因**:
- Schema 注释不完整 → LLM 无法理解字段语义
- 向量检索召回表错误 → 降低 `score_threshold`
- Temperature 过高 → 设为 0 或 0.1
**解决**:
1. 补充 Schema 字段注释
2. 重建向量索引
3. 启用 Few-Shot 并增加高评分样本
---
### 4. 日期函数错误(MySQL 风格)
**现象**:生成 `WHERE date >= CURDATE()` 而非 T-SQL 风格。
**解决**:系统已内置 `rewrite_mysql_builtins_for_tsql` 自动替换,但仍需确保 Prompt 约束。检查 `config/prompts.py` 中 T-SQL 约束是否完整。
---
### 5. 外键缺失导致 JOIN 失败
**现象**:SQL 使用 `JOIN` 但缺少 `ON` 条件,或关联表未纳入。
**解决**:
- 检查 Schema 中 `foreign_keys` 定义是否完整
- 向量检索可能遗漏关联表 → 启用外键扩展(默认开启)
- 手动在 Prompt 中强调 JOIN 完整性
---
## 🎓 Prompt 设计哲学
### 原则1:明确约束,禁止猜测
```python
"只提取明确信息,禁止猜测:仅实现用户问题里明确写出的筛选条件,"
"不可自行推断或补充未提及的筛选条件。"
```
**反面示例**:用户问"2024年1月的销售额",不应推断为"2024年1月1日至1月31日"(除非 Schema 有相应字段)。
---
### 原则2:提供推断指南
当无法避免推断时,提供**明确的推断规则**:
```python
**常见时间/状态推断指南**(需结合 Schema 字段注释):
- "2024年1月" → WHERE date_col >= '2024-01-01' AND date_col < '2024-02-01'
- "今天" / "当日" → WHERE date_col >= CAST(GETDATE() AS DATE)
AND date_col < DATEADD(DAY,1,CAST(GETDATE() AS DATE))
- "活跃" → 通常对应 State = 'A'(需确认 Schema 注释)
- "未结算" → 通常对应 SettleStatus = 'U' 或 Settled = 0
```
---
### 原则3:Few-Shot 示范优于文字描述
LLM 更擅长模仿示例而非理解抽象规则。提供 5-7 个高质量示例覆盖常见模式:
- 示例 3:日期范围推断
- 示例 4:状态值推断
- 示例 5:聚合 + 排序
- 示例 6:当日查询(GETDATE())
- 示例 7:LEFT JOIN 取维度名称
---
### 原则4:结构化输出要求
```python
输出格式:严格 JSON
{
"relevant_tables": ["TableA", "TableB"],
"reasoning": "选择理由(50-100字)"
}
```
避免自由文本,便于程序解析。
---
## 📝 开发日志
### v0.2.0(2026-04-10)—— Few-Shot 增强版
- ✅ 集成经验数据集(50 条标注样本)
- ✅ 实现 Few-Shot 选择器(语义/关键词双模式)
- ✅ 动态注入相似示例到 Prompt
- ✅ 优化 Prompt:允许合理推断,禁止随意猜测
- ✅ 添加 5 个新 Few-Shot 示例(日期、状态、聚合等)
- ✅ 降低向量检索阈值(0.2 → 0.1),提升召回率
- ✅ 确定性模式(TEMPERATURE=0, MAX_RETRY=1)
- ✅ 修复 Unicode 编码问题(Windows 控制台)
---
### v0.1.0(2026-04-08)—— 基础版本
- 🎉 初始发布
- 三 Agent 流水线(Schema Linker / SQL Generator / Validator)
- 向量检索 + LLM 精筛表选择
- ChromaDB + Qwen3-Embedding 本地索引
- T-SQL / MySQL / PostgreSQL 多方言支持
- 双重验证机制(程序 + LLM)
- 自修正重试(最多 2 次)
---
## 📄 许可证
MIT License — 详见 [LICENSE](LICENSE) 文件。
## 🙏 致谢
- [CAMEL AI](https://www.camel-ai.org/) — 多 Agent 框架
- [DeepSeek](https://platform.deepseek.com/) — 大模型 API
- [Qwen](https://qwen.ai/) — Embedding 模型
- [ChromaDB](https://www.trychroma.com/) — 向量数据库
- [sqlglot](https://sqlglot.com/) — SQL 解析与转换
---
**维护者**:Text2SQL Team
**更新日期**:2026-04-10
**文档版本**:v0.2.0
+5
View File
@@ -0,0 +1,5 @@
# Text-to-SQL Multi-Agent System
# 基于 CAMEL AI + DeepSeek + Qwen3-Embedding 的智能SQL生成系统
__version__ = "0.1.0"
__author__ = "Backman Team"
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
# agents 包初始化
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+558
View File
@@ -0,0 +1,558 @@
"""
Text2SQL 多智能体编排器
协调 Schema Linker、SQL Generator、Validator 三个Agent
"""
import logging
import os # 新增
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass, field
from schema.manager import SchemaManager
from schema.indexer import SchemaIndexer
from llm.deepseek_client import DeepSeekClient, DeepSeekConfig
from utils.fewshot_selector import FewShotSelector # 新增
logger = logging.getLogger(__name__)
@dataclass
class GenerationResult:
"""SQL生成结果"""
sql: str
valid: bool
errors: List[str] = field(default_factory=list)
warnings: List[str] = field(default_factory=list)
tables_used: List[str] = field(default_factory=list)
attempts: int = 1
reasoning: Optional[str] = None
metadata: Dict[str, any] = field(default_factory=dict)
class Text2SQLOrchestrator:
"""
Text2SQL 多智能体编排器
工作流程:
1. Schema Linker:粗筛 + LLM精筛,选出相关表
2. 外键扩展:自动包含关联表
3. SQL Generator:生成SQL
4. Validator:验证SQL,不通过则重试(最多max_retry次)
"""
def __init__(
self,
schema_manager: SchemaManager,
deepseek_api_key: Optional[str] = None,
deepseek_config: Optional[DeepSeekConfig] = None,
embedding_model_path: Optional[str] = None,
vector_db_path: str = "./data/embeddings/chroma",
max_retry: int = 2,
use_vector_search: bool = True,
# Few-shot配置
fewshot_enabled: bool = True,
fewshot_samples_path: Optional[str] = None,
fewshot_top_k: int = 3,
fewshot_min_rating: int = 7,
):
"""
初始化编排器
Args:
schema_manager: Schema管理器实例
deepseek_api_key: DeepSeek API密钥(也可通过环境变量DEEPSEEK_API_KEY)
deepseek_config: DeepSeek配置对象(优先于api_key)
embedding_model_path: Qwen3-Embedding模型路径
vector_db_path: 向量数据库路径
max_retry: 最大重试次数(包含首次生成)
use_vector_search: 是否使用向量检索粗筛
"""
self.schema_manager = schema_manager
self.max_retry = max_retry
self.use_vector_search = use_vector_search
# 初始化DeepSeek客户端
if deepseek_config:
self.deepseek = DeepSeekClient(deepseek_config)
else:
self.deepseek = DeepSeekClient(
DeepSeekConfig(api_key=deepseek_api_key)
)
# 初始化向量索引(延迟加载)
self._vector_index: Optional[SchemaIndexer] = None
self._vector_db_path = vector_db_path
self._embedding_model_path = embedding_model_path
# Few-shot 初始化
self.fewshot_enabled = fewshot_enabled
self.fewshot_top_k = fewshot_top_k
self.fewshot_min_rating = fewshot_min_rating
self.fewshot_selector = None
if self.fewshot_enabled:
try:
path = fewshot_samples_path or os.getenv(
"FEWSHOT_DATA_PATH",
"./data/experiences/all_samples.jsonl"
)
self.fewshot_selector = FewShotSelector(
path,
embedding_model_path=self._embedding_model_path,
)
logger.info(
f"Few-shot已启用: top_k={fewshot_top_k}, "
f"min_rating={fewshot_min_rating}"
)
except Exception as e:
logger.warning(f"Few-shot加载失败: {e},将使用标准生成")
self.fewshot_enabled = False
logger.info(
f"[OK] Text2SQLOrchestrator初始化完成: "
f"max_retry={max_retry}, use_vector_search={use_vector_search}"
+ (f", fewshot=on" if self.fewshot_enabled else "")
)
def _get_vector_index(self) -> SchemaIndexer:
"""获取或创建向量索引(懒加载)"""
if self._vector_index is None:
from utils.embedding import get_embedder
embedder = get_embedder(self._embedding_model_path)
self._vector_index = SchemaIndexer(
embedder=embedder,
persist_dir=self._vector_db_path
)
return self._vector_index
def _coarse_filter(
self,
question: str,
top_k: int = 20
) -> List[str]:
"""
阶段1:粗筛(向量检索)
Args:
question: 用户问题
top_k: 返回前K个候选表
Returns:
候选表名列表
"""
if not self.use_vector_search:
# 不使用向量检索时,返回所有表
return self.schema_manager.list_tables()
indexer = self._get_vector_index()
# 确保索引已构建
if indexer.count() == 0:
logger.info("向量索引为空,正在构建...")
indexer.build_index(self.schema_manager, force_rebuild=True)
# 检索
results = indexer.search(
query=question,
top_k=top_k,
score_threshold=0.1 # 降低阈值以提高召回率(原0.2)
)
candidate_tables = [r["table_name"] for r in results]
logger.debug(f"粗筛候选表:{candidate_tables[:10]}...(共{len(candidate_tables)}个)")
return candidate_tables
def _llm_select_tables(
self,
question: str,
candidate_tables: List[str],
max_tables: int = 5
) -> Tuple[List[str], str]:
"""
阶段2:LLM精筛(Schema Linker Agent)
Args:
question: 用户问题
candidate_tables: 候选表列表
max_tables: 最多选择的表数
Returns:
(相关表列表, 推理理由)
"""
# 构造候选表信息(只显示表名和注释)
table_infos = []
for tbl_name in candidate_tables:
table = self.schema_manager.get_table(tbl_name)
if table:
comment = table.comment or "无描述"
table_infos.append(f"- {tbl_name}: {comment}")
table_list_str = "\n".join(table_infos)
# 使用DeepSeek客户端调用(而非CAMEL Agent,更直接可控)
response = self.deepseek.select_tables(
question=question,
table_list=table_list_str
)
relevant_tables = response.get("relevant_tables", [])
reasoning = response.get("reasoning", "")
# 限制数量
relevant_tables = relevant_tables[:max_tables]
logger.info(f"LLM精筛选中表:{relevant_tables}")
return relevant_tables, reasoning
_BROKER_KEYWORDS_CN = ("对手方", "经纪商", "券商", "對手方")
def _question_implies_broker_dimension(self, question: str) -> bool:
if not question:
return False
if any(k in question for k in self._BROKER_KEYWORDS_CN):
return True
return "broker" in question.lower()
def _prioritize_broker_tables(
self, question: str, relevant_tables: List[str], max_tables: int = 5
) -> List[str]:
"""
问题涉及对手方/经纪商时,优先纳入 TSBBrokerContract 与 MCBroker(若 Schema 中存在),
避免仅选中 VSBHK 报表视图却无 BrokerID,模型又照抄黄金范例列名导致校验失败。
"""
if not self._question_implies_broker_dimension(question):
return relevant_tables[:max_tables]
priority = ["TSBBrokerContract", "MCBroker"]
present = [t for t in priority if self.schema_manager.get_table(t)]
if not present:
return relevant_tables[:max_tables]
seen = set()
merged: List[str] = []
for t in present:
if t not in seen:
merged.append(t)
seen.add(t)
for t in relevant_tables:
if len(merged) >= max_tables:
break
if t not in seen and self.schema_manager.get_table(t):
merged.append(t)
seen.add(t)
logger.info("对手方/经纪商问题:优先纳入 %s,调整后选表:%s", present, merged)
return merged[:max_tables]
def _expand_relations(self, table_names: List[str]) -> List[str]:
"""
外键扩展:自动添加关联表
Args:
table_names: 已选中的表名列表
Returns:
扩展后的表名列表
"""
result = set(table_names)
for tbl_name in table_names:
table = self.schema_manager.get_table(tbl_name)
if not table:
continue
# 添加被引用的表(外键指向的表)
for fk in table.foreign_keys:
if fk.ref_table not in result:
result.add(fk.ref_table)
logger.debug(f"外键扩展:添加关联表 {fk.ref_table}")
# 添加引用当前表的表(反向外键)
for other in self.schema_manager.get_tables():
for fk in other.foreign_keys:
if fk.ref_table == tbl_name and other.name not in result:
result.add(other.name)
logger.debug(f"外键扩展:添加引用表 {other.name}")
expanded = list(result)
if len(expanded) > len(table_names):
logger.info(f"外键扩展:{table_names} → {expanded}")
return expanded
def _generate_sql(
self,
question: str,
schema_str: str,
dialect: str = "tsql"
) -> str:
"""
SQL生成(SQL Generator Agent)
Args:
question: 用户问题
schema_str: Schema描述字符串
dialect: SQL方言
Returns:
SQL语句
"""
from config.prompts import SQL_GENERATOR_SYSTEM, SQL_GENERATOR_USER
from utils.sql_parser import normalize_sql_for_dialect
# Few-shot 增强
if self.fewshot_enabled and self.fewshot_selector:
try:
examples = self.fewshot_selector.select(
question=question,
top_k=self.fewshot_top_k,
min_rating=self.fewshot_min_rating
)
if examples:
examples_prompt = "\n\n".join([
f"示例 {i+1}:\n问题:{ex.question_zh}\nSQL:\n{ex.sql}"
for i, ex in enumerate(examples)
])
schema_str = f"参考以下相似示例的SQL编写风格:\n\n{examples_prompt}\n\n【当前Schema】\n{schema_str}"
logger.debug(f"已注入 {len(examples)} 个few-shot示例: {[ex.qid for ex in examples]}")
except Exception as e:
logger.warning(f"Few-shot检索失败: {e}")
dialect_label = dialect
if dialect == "tsql":
dialect_label = "Microsoft SQL Server (T-SQL)"
user_content = SQL_GENERATOR_USER.format(
schema=schema_str,
question=question,
dialect=dialect_label,
)
if dialect == "tsql":
user_content += (
"\n\n【硬性要求】目标库为 SQL Server(T-SQL):禁止使用 MySQL 反引号 `;"
"标识符如需引用请使用方括号,例如 [TableName]、[ColumnName]。"
"字符串连接使用 `+`(与系统提示中的标准版式范例一致)。"
"「今日」「当天」等与日期列比较时,使用 `CAST(GETDATE() AS DATE)`,"
"**禁止** `CURDATE()`、`NOW()`、`CURRENT_DATE`(MySQL)。"
"条件请使用 T-SQL 惯用写法(例如 IS NOT NULL)。"
"排版仍须遵守:关键字大写、SELECT 每列一行缩进、WHERE 续行以 AND 开头、PascalCase 英文别名。"
)
messages = [
{"role": "system", "content": SQL_GENERATOR_SYSTEM},
{"role": "user", "content": user_content},
]
response = self.deepseek.chat(messages)
sql = response.content.strip()
# 清理可能的markdown代码块
if "```sql" in sql:
sql = sql[sql.find("```sql") + 6:sql.find("```", sql.find("```sql") + 6)].strip()
elif "```" in sql:
sql = sql[sql.find("```") + 3:sql.find("```", sql.find("```") + 3)].strip()
sql = normalize_sql_for_dialect(sql, dialect)
logger.debug(f"生成的SQL:{sql[:200]}...")
return sql
def _validate_sql(
self,
sql: str,
schema_str: str,
dialect: str = "tsql",
) -> Tuple[bool, List[str], List[str]]:
"""
SQL验证(Validator Agent + 程序验证)
Args:
sql: SQL语句
schema_str: Schema描述
dialect: 与生成一致的 SQL 方言(sqlglot 名,默认 tsql)
Returns:
(是否通过, 错误列表, 警告列表)
"""
errors = []
warnings = []
# === 阶段1:程序验证(确定性规则) ===
from utils.sql_parser import validate_sql_syntax, validate_schema_consistency
# 语法验证
syntax_ok, syntax_errors = validate_sql_syntax(sql, dialect=dialect)
if not syntax_ok:
errors.extend(syntax_errors)
# Schema一致性验证
schema_ok, schema_errors = validate_schema_consistency(
sql, self.schema_manager, dialect=dialect
)
if not schema_ok:
errors.extend(schema_errors)
# 危险操作检查
from utils.validators import check_dangerous_operations
danger_ok, danger_errors = check_dangerous_operations(sql)
if not danger_ok:
errors.extend(danger_errors)
# === 阶段2:LLM语义验证 ===
try:
llm_result = self.deepseek.validate_sql(sql=sql, schema=schema_str)
llm_errors = list(llm_result.get("errors", []))
# 程序校验已通过表/列(含别名解析)时,LLM 仍常误报 unknown_*,避免误杀整次生成
if schema_ok:
llm_errors = [
e
for e in llm_errors
if isinstance(e, str)
and not (
e.startswith("unknown_table:")
or e.startswith("unknown_column:")
)
]
if not llm_result.get("valid", True):
errors.extend(llm_errors)
warnings.extend(llm_result.get("warnings", []))
suggestions = llm_result.get("suggestions", [])
if suggestions:
logger.debug(f"优化建议:{suggestions}")
except Exception as e:
logger.warning(f"LLM验证失败(降级为仅程序验证): {e}")
is_valid = len(errors) == 0
return is_valid, errors, warnings
def generate(
self,
question: str,
dialect: str = "tsql",
top_k_candidates: int = 20,
include_schema_in_result: bool = False
) -> GenerationResult:
"""
主生成流程
Args:
question: 用户自然语言问题
dialect: SQL方言(默认 tsql;与 sqlglot 一致)
top_k_candidates: 粗筛候选表数量
include_schema_in_result: 结果中是否包含使用的Schema字符串
Returns:
GenerationResult对象
"""
logger.info(f"[GEN] 开始生成SQL:{question[:50]}...")
attempt = 0
last_sql = None
last_errors = []
filtered_schema_str = ""
tables_used = []
while attempt < self.max_retry:
logger.info(f" 尝试 #{attempt + 1}")
# === Step 1: Schema筛选(仅首次) ===
if attempt == 0:
# 1.1 粗筛
candidate_tables = self._coarse_filter(question, top_k=top_k_candidates)
# 1.2 LLM精筛
relevant_tables, reasoning = self._llm_select_tables(question, candidate_tables)
relevant_tables = self._prioritize_broker_tables(question, relevant_tables)
# 1.3 外键扩展
expanded_tables = self._expand_relations(relevant_tables)
tables_used = expanded_tables
# 1.4 生成Schema字符串
filtered_schema_str = self.schema_manager.to_compact_string(
table_names=expanded_tables,
include_columns=True,
max_columns_per_table=20
)
logger.info(f" 选中表:{relevant_tables},扩展后:{expanded_tables}")
else:
# 重试时复用之前的Schema
logger.info(f" 重试使用之前的Schema({len(tables_used)}张表)")
# === Step 2: SQL生成 ===
try:
sql = self._generate_sql(question, filtered_schema_str, dialect)
last_sql = sql
except Exception as e:
last_errors = [f"SQL生成失败: {str(e)}"]
attempt += 1
continue
# === Step 3: 验证 ===
is_valid, errors, warnings = self._validate_sql(
sql, filtered_schema_str, dialect=dialect
)
if is_valid:
logger.info(f"[OK] SQL生成并验证通过({attempt + 1}次尝试)")
result = GenerationResult(
sql=sql,
valid=True,
errors=[],
warnings=warnings,
tables_used=tables_used,
attempts=attempt + 1,
reasoning=reasoning if attempt == 0 else None,
)
if include_schema_in_result:
result.metadata["schema"] = filtered_schema_str
return result
# 验证失败,准备重试
last_errors = errors
logger.warning(f" [FAIL] 验证失败:{errors}")
attempt += 1
# 达到最大重试次数
logger.error(f"[FAIL] 达到最大重试次数({self.max_retry}),生成失败")
return GenerationResult(
sql=last_sql or "",
valid=False,
errors=last_errors,
tables_used=tables_used,
attempts=attempt,
)
def build_vector_index(self, force_rebuild: bool = False) -> bool:
"""
构建向量索引(可选,提前构建可加速首次查询)
Args:
force_rebuild: 是否强制重建
Returns:
是否成功构建
"""
indexer = self._get_vector_index()
return indexer.build_index(
self.schema_manager,
force_rebuild=force_rebuild
)
def get_statistics(self) -> Dict:
"""获取统计信息"""
schema_stats = self.schema_manager.get_statistics()
indexer = self._get_vector_index()
index_stats = indexer.get_statistics()
return {
"schema": schema_stats,
"vector_index": index_stats,
"max_retry": self.max_retry,
"use_vector_search": self.use_vector_search,
}
+163
View File
@@ -0,0 +1,163 @@
"""
Schema Linker Agent - 表筛选专家
从大量数据表中识别与用户问题相关的表
"""
import logging
from typing import Dict, List, Tuple, Optional
import json
from camel.agents import ChatAgent
from camel.models import ChatModel
from config.prompts import SCHEMA_LINKER_SYSTEM
logger = logging.getLogger(__name__)
class SchemaLinkerAgent:
"""
Schema Linker Agent
职责:
- 分析用户问题中的实体和意图
- 从候选表中筛选真正相关的表
- 提供选择理由
"""
def __init__(
self,
model: ChatModel,
system_message: Optional[str] = None
):
"""
初始化Agent
Args:
model: CAMEL AI模型实例
system_message: 系统提示词(默认使用SCHEMA_LINKER_SYSTEM)
"""
self.system_message = system_message or SCHEMA_LINKER_SYSTEM
self.agent = ChatAgent(
system_message=self.system_message,
model=model,
)
logger.info("[OK] SchemaLinkerAgent初始化完成")
def select_tables(
self,
question: str,
candidate_tables: List[str],
table_metadata: Optional[Dict[str, str]] = None,
max_tables: int = 5
) -> Tuple[List[str], str]:
"""
选择相关表
Args:
question: 用户问题
candidate_tables: 候选表列表(粗筛结果)
table_metadata: 表元数据 {表名: 注释}
max_tables: 最多返回表数量
Returns:
(相关表列表, 推理理由)
"""
# 构造候选表信息字符串
if table_metadata:
table_list = "\n".join([
f"- {tbl}: {table_metadata.get(tbl, '无描述')}"
for tbl in candidate_tables
])
else:
table_list = "\n".join([f"- {tbl}" for tbl in candidate_tables])
from config.prompts import SCHEMA_LINKER_USER
prompt = SCHEMA_LINKER_USER.format(
question=question,
table_list=table_list
)
try:
response = self.agent.step(prompt)
content = response.msg.content.strip()
# 解析JSON响应
result = self._parse_json_response(content)
relevant_tables = result.get("relevant_tables", [])
reasoning = result.get("reasoning", "")
# 限制数量
relevant_tables = relevant_tables[:max_tables]
logger.info(
f"SchemaLinker选中 {len(relevant_tables)} 张表: {relevant_tables}"
)
return relevant_tables, reasoning
except json.JSONDecodeError as e:
logger.error(f"JSON解析失败: {e}, 原始内容: {content[:200]}")
# 降级:返回前max_tables个候选表
return candidate_tables[:max_tables], "JSON解析失败,使用粗筛结果"
except Exception as e:
logger.error(f"Agent调用失败: {e}")
return candidate_tables[:max_tables], f"Agent错误: {str(e)}"
def _parse_json_response(self, content: str) -> Dict:
"""
解析Agent的JSON响应
处理可能的markdown代码块包裹
"""
import json
# 尝试提取```json```块
if "```json" in content:
start = content.find("```json") + 7
end = content.find("```", start)
if end != -1:
content = content[start:end].strip()
elif "```" in content:
start = content.find("```") + 3
end = content.find("```", start)
if end != -1:
content = content[start:end].strip()
return json.loads(content)
def expand_by_relations(
self,
selected_tables: List[str],
schema_manager,
depth: int = 1
) -> List[str]:
"""
通过外键关系扩展表(备选方案,也可在Orchestrator中完成)
Args:
selected_tables: 已选中的表
schema_manager: Schema管理器
depth: 递归深度
Returns:
扩展后的表列表
"""
result = set(selected_tables)
for tbl_name in selected_tables:
table = schema_manager.get_table(tbl_name)
if not table:
continue
# 外键指向的表
for fk in table.foreign_keys:
if fk.ref_table not in result:
result.add(fk.ref_table)
# 引用当前表的表(反向外键)
for other in schema_manager.get_tables():
for fk in other.foreign_keys:
if fk.ref_table == tbl_name and other.name not in result:
result.add(other.name)
return list(result)
+206
View File
@@ -0,0 +1,206 @@
"""
SQL Generator Agent - SQL生成专家
根据Schema和问题生成高质量SQL
"""
import logging
import json
import re
from typing import Dict, Optional
from camel.agents import ChatAgent
from camel.models import ChatModel
from config.prompts import SQL_GENERATOR_SYSTEM
logger = logging.getLogger(__name__)
class SQLGeneratorAgent:
"""
SQL Generator Agent
职责:
- 理解用户问题和Schema结构
- 生成准确的SQL语句
- 处理复杂的JOIN、聚合、子查询
- 遵循金融/证券业务特殊规则
"""
def __init__(
self,
model: ChatModel,
system_message: Optional[str] = None,
dialect: str = "tsql"
):
"""
初始化Agent
Args:
model: CAMEL AI模型实例
system_message: 系统提示词
dialect: SQL方言
"""
self.dialect = dialect
self.system_message = system_message or SQL_GENERATOR_SYSTEM
self.agent = ChatAgent(
system_message=self.system_message,
model=model,
)
logger.info(f"[OK] SQLGeneratorAgent初始化完成 (dialect={dialect})")
def generate(
self,
question: str,
schema_str: str,
examples: Optional[List[Dict]] = None,
dialect: Optional[str] = None
) -> str:
"""
生成SQL
Args:
question: 用户问题
schema_str: Schema描述字符串
examples: Few-shot示例列表
dialect: 覆盖默认dialect
Returns:
SQL语句字符串
"""
from config.prompts import SQL_GENERATOR_USER
dialect = dialect or self.dialect
prompt = SQL_GENERATOR_USER.format(
schema=schema_str,
question=question,
dialect=dialect
)
# 添加few-shot示例(如果有)
if examples:
prompt = self._inject_examples(prompt, examples)
try:
response = self.agent.step(prompt)
sql = self._extract_sql(response.msg.content)
logger.debug(f"生成的SQL: {sql[:200]}...")
return sql
except Exception as e:
logger.error(f"SQL生成失败: {e}")
raise
def _extract_sql(self, content: str) -> str:
"""
从Agent响应中提取SQL语句
处理:
- Markdown代码块 (```sql ... ```)
- 纯SQL文本
- JSON格式 {"sql": "..."}
"""
content = content.strip()
# 尝试提取```sql```块
if "```sql" in content:
start = content.find("```sql") + 6
end = content.find("```", start)
if end != -1:
return content[start:end].strip()
# 尝试提取通用代码块```
if "```" in content:
start = content.find("```") + 3
end = content.find("```", start)
if end != -1:
return content[start:end].strip()
# 尝试解析JSON
try:
data = json.loads(content)
if "sql" in data:
return data["sql"]
except json.JSONDecodeError:
pass
# 返回原始内容(假设是纯SQL)
return content
def _inject_examples(
self,
prompt: str,
examples: List[Dict]
) -> str:
"""
注入few-shot示例到提示词
Args:
prompt: 原始提示词
examples: 示例列表,每项为 {"question": "...", "schema": "...", "sql": "..."}
Returns:
增强后的提示词
"""
examples_text = []
for ex in examples[:3]: # 最多3个示例
examples_text.append(
f"示例:\n问题:{ex['question']}\n"
f"Schema: {ex['schema'][:200]}...\n"
f"SQL: {ex['sql']}"
)
examples_block = "\n\n".join(examples_text)
# 插入到提示词末尾(要求之前)
return f"{prompt}\n\n参考示例:\n{examples_block}\n\n请生成SQL:"
def generate_with_reasoning(
self,
question: str,
schema_str: str,
dialect: Optional[str] = None
) -> Tuple[str, str]:
"""
生成SQL并返回解释
Args:
question: 用户问题
schema_str: Schema描述
dialect: SQL方言
Returns:
(SQL语句, 解释)
"""
from config.prompts import SQL_GENERATOR_USER
dialect = dialect or self.dialect
prompt = f"""
{sql_generator_user.format(schema=schema_str, question=question, dialect=dialect)}
请同时输出SQL和简要解释(JSON格式):
{{
"sql": "SELECT ...",
"explanation": "SQL逻辑说明"
}}
"""
try:
response = self.agent.step(prompt)
content = response.msg.content.strip()
# 尝试解析JSON
try:
if "```json" in content:
start = content.find("```json") + 7
end = content.find("```", start)
content = content[start:end].strip()
data = json.loads(content)
return data.get("sql", ""), data.get("explanation", "")
except (json.JSONDecodeError, ValueError):
# 降级:提取SQL,解释为空
return self._extract_sql(content), ""
except Exception as e:
logger.error(f"生成失败: {e}")
raise
+299
View File
@@ -0,0 +1,299 @@
"""
Validator Agent - SQL审核员
验证SQL的正确性和安全性
"""
import logging
import json
from typing import Dict, List, Tuple, Optional
from camel.agents import ChatAgent
from camel.models import ChatModel
from config.prompts import VALIDATOR_SYSTEM
from utils.validators import full_validation_pipeline
from utils.sql_parser import validate_sql_syntax, validate_schema_consistency
logger = logging.getLogger(__name__)
class ValidatorAgent:
"""
Validator Agent
职责:
- 语法正确性验证
- Schema一致性检查
- 安全性检查(禁止DML/DDL)
- 性能问题识别
- 提供修正建议
"""
def __init__(
self,
model: ChatModel,
system_message: Optional[str] = None,
schema_manager = None
):
"""
初始化Agent
Args:
model: CAMEL AI模型实例
system_message: 系统提示词
schema_manager: Schema管理器(程序验证用)
"""
self.schema_manager = schema_manager
self.system_message = system_message or VALIDATOR_SYSTEM
self.agent = ChatAgent(
system_message=self.system_message,
model=model,
)
logger.info("[OK] ValidatorAgent初始化完成")
def validate(
self,
sql: str,
schema_str: str,
dialect: str = "tsql",
check_dangerous: bool = True
) -> Dict:
"""
完整验证流程(程序 + LLM双重验证)
Args:
sql: SQL语句
schema_str: Schema描述
dialect: SQL方言
check_dangerous: 是否检查危险操作
Returns:
验证结果字典 {
"valid": bool,
"errors": [...],
"warnings": [...],
"suggestions": [...]
}
"""
result = {
"valid": True,
"errors": [],
"warnings": [],
"suggestions": []
}
# === 阶段1:程序验证(快速、确定性) ===
program_result = self._program_validation(
sql, dialect, check_dangerous
)
result["errors"].extend(program_result.get("errors", []))
result["warnings"].extend(program_result.get("warnings", []))
result["suggestions"].extend(program_result.get("suggestions", []))
# 如果程序验证已发现致命错误,跳过LLM验证
if program_result.get("fatal", False):
result["valid"] = False
return result
# === 阶段2:LLM语义验证 ===
try:
llm_result = self._llm_validation(sql, schema_str)
result["errors"].extend(llm_result.get("errors", []))
result["warnings"].extend(llm_result.get("warnings", []))
result["suggestions"].extend(llm_result.get("suggestions", []))
except Exception as e:
logger.warning(f"LLM验证失败,使用程序验证结果: {e}")
result["warnings"].append(f"LLM验证异常: {str(e)}")
result["valid"] = len(result["errors"]) == 0
return result
def _program_validation(
self,
sql: str,
dialect: str,
check_dangerous: bool
) -> Dict:
"""
程序验证(规则引擎)
Returns:
{"errors": [], "warnings": [], "suggestions": [], "fatal": bool}
"""
errors = []
warnings = []
suggestions = []
fatal = False
# 1. 语法检查
syntax_ok, syntax_errors = validate_sql_syntax(sql, dialect)
if not syntax_ok:
errors.extend(syntax_errors)
fatal = True # 语法错误无法修复,直接失败
return {
"errors": errors, "warnings": warnings,
"suggestions": suggestions, "fatal": fatal
}
# 2. Schema一致性(如果有schema_manager)
if self.schema_manager:
schema_ok, schema_errors = validate_schema_consistency(
sql, self.schema_manager, dialect
)
if not schema_ok:
errors.extend(schema_errors)
# Schema错误通常也是fatal的
fatal = True
# 3. 危险操作检查
if check_dangerous:
from utils.validators import check_dangerous_operations
safe, dangers = check_dangerous_operations(sql)
if not safe:
errors.append(f"包含危险操作: {', '.join(dangers)}")
fatal = True
return {
"errors": errors,
"warnings": warnings,
"suggestions": suggestions,
"fatal": fatal
}
def _llm_validation(self, sql: str, schema_str: str) -> Dict:
"""
LLM语义验证
Args:
sql: SQL语句
schema_str: Schema描述
Returns:
验证结果
"""
from config.prompts import VALIDATOR_USER
prompt = VALIDATOR_USER.format(sql=sql, schema=schema_str)
try:
response = self.agent.step(prompt)
content = response.msg.content.strip()
# 解析JSON响应
result = self._parse_json_response(content)
# 标准化字段
return {
"errors": result.get("errors", []),
"warnings": result.get("warnings", []),
"suggestions": result.get("suggestions", []),
}
except Exception as e:
logger.error(f"LLM验证异常: {e}")
return {
"errors": [f"LLM验证失败: {str(e)}"],
"warnings": [],
"suggestions": []
}
def _parse_json_response(self, content: str) -> Dict:
"""解析JSON响应"""
try:
# 提取```json```块
if "```json" in content:
start = content.find("```json") + 7
end = content.find("```", start)
if end != -1:
content = content[start:end].strip()
return json.loads(content)
except json.JSONDecodeError as e:
logger.warning(f"JSON解析失败: {e}, content={content[:200]}")
return {"errors": ["验证结果解析失败"], "warnings": [], "suggestions": []}
def quick_check(self, sql: str) -> Tuple[bool, List[str]]:
"""
快速检查(仅语法和危险操作)
Returns:
(是否通过, 错误列表)
"""
errors = []
# 语法
syntax_ok, syntax_errors = validate_sql_syntax(sql)
if not syntax_ok:
errors.extend(syntax_errors)
return False, errors
# 危险操作
from utils.validators import check_dangerous_operations
safe, dangers = check_dangerous_operations(sql)
if not safe:
errors.append(f"危险操作: {', '.join(dangers)}")
return False, errors
return True, []
def suggest_fixes(
self,
sql: str,
errors: List[str],
schema_str: str
) -> List[str]:
"""
根据错误建议修复方案
Args:
sql: 原始SQL
errors: 错误列表
schema_str: Schema描述
Returns:
修复建议列表
"""
suggestions = []
# 常见错误模式匹配
for error in errors:
error_lower = error.lower()
if "field not exist" in error_lower or "字段不存在" in error_lower:
suggestions.append(
"建议:检查字段名拼写,或使用schema_manager.get_table(table).column_names查看可用字段"
)
if "table not exist" in error_lower or "表不存在" in error_lower:
suggestions.append(
"建议:检查表名拼写,或使用schema_manager.list_tables()查看所有表"
)
if "missing join condition" in error_lower or "缺少on条件" in error_lower:
suggestions.append(
"建议:为每个JOIN添加明确的ON条件,基于外键关系"
)
if "group by" in error_lower:
suggestions.append(
"建议:SELECT中的所有非聚合字段都必须出现在GROUP BY子句中"
)
# LLM补充建议
if len(suggestions) < len(errors):
try:
prompt = f"""
SQL: {sql}
错误: {errors}
Schema: {schema_str[:1000]}
请给出2-3条具体的修复建议(简洁明了):
"""
response = self.agent.step(prompt)
llm_suggestions = response.msg.content.strip().split('\n')
suggestions.extend([s for s in llm_suggestions if s.strip()])
except Exception as e:
logger.warning(f"获取LLM建议失败: {e}")
return suggestions[:5] # 最多5条
+1
View File
@@ -0,0 +1 @@
# config 包初始化
Binary file not shown.
Binary file not shown.
Binary file not shown.
+321
View File
@@ -0,0 +1,321 @@
"""
Prompt模板配置
"""
from typing import Dict
# ========== Schema Linker Agent Prompt ==========
SCHEMA_LINKER_SYSTEM = """你是一个经验丰富的数据库架构师,专门负责数据库表结构分析与关联。
**任务**:从大量数据表中识别与用户问题相关的表。
**硬性约束(必须遵守)**:
1. **只依据明确信息**:仅根据用户问题中**清楚写出的**实体、指标、时间范围、业务对象选表;不要为「可能还需要」的维度擅自加表。
2. **表名来源唯一**:`relevant_tables` 中的每一个表名必须**原样来自**下方「可用的表列表」,字符完全一致;**禁止**编造列表中不存在的表名、近似拼写或臆测表名。
3. **中英对照**:若用户混用中英文,仅允许对问题里**已出现的**中文业务词做合理对应到列表中的英文表名;**不得**因翻译而引入列表外的表。
4. **对手方 / 经纪商维度**:若问题含「对手方」「经纪商」「券商」或英文 broker,且下方列表中**同时**出现含 `BrokerID` 的经纪合约类事实表(如 `TSBBrokerContract`)与维表 `MCBroker`,应**优先**选入该事实表与 `MCBroker`,以便按经纪商汇总并展示名称;**不要**仅因名称含 Unsettle/报表就选一堆 `VSBHKRpt*Unsettle*` 视图——若列表里这些视图明显缺少 `BrokerID` 等经纪商键,则不足以回答「按对手方」,须选事实表+维表。
**工作流程**:
1. 分析问题中的实体(名词、概念)和操作(查询、统计、比较等)
2. 从提供的Schema信息中匹配可能的表(基于表名、表注释、字段名、字段注释)
3. 考虑表间外键关系,确保JOIN完整性(不要漏掉关联表)
4. 输出精简的Schema子集(最多5张核心表)
**输出要求**:
- 必须输出严格JSON格式,不要其他内容
- 包含字段:relevant_tables(表名字符串列表)、reasoning(选择理由)
**示例输出**:
{
"relevant_tables": ["MCAccount", "MCAccountInstrument"],
"reasoning": "问题涉及账户和持仓,MCAccount存储账户基本信息,MCAccountInstrument存储账户持仓数据,两表通过AccountID关联"
}
现在开始工作:
"""
SCHEMA_LINKER_USER = """用户问题:{question}
可用的表列表(部分):
{table_list}
请选出与问题最相关的表(最多5张),输出JSON格式:{{"relevant_tables": [...], "reasoning": "..."}}"""
# ========== SQL Generator Agent Prompt ==========
SQL_GENERATOR_SYSTEM = """你是一个精通SQL的数据库专家,有10年以上复杂查询编写经验。
**任务**:根据提供的数据库Schema和用户问题,生成准确、高效的SQL语句。
**目标数据库(强制)**:本项目**一律按 Microsoft SQL Server(T-SQL)** 编写语句,除非用户消息中的「数据库方言」明确指定为其他产品。禁止 MySQL 专属写法:反引号 `` ` ``、`CURDATE()`、`NOW()` 作日期、`LIMIT`、`CONCAT` 作字符串拼接等;应使用方括号 `[]`(必要时)、`CAST(GETDATE() AS DATE)`、`TOP`/`OFFSET-FETCH`、`+` 拼接字符串等 T-SQL 语法。
**何为「有用 SQL」(合格输出的唯一标准)**:
- 必须是**可直接执行**、且与下方 **「业务级黄金范例」** **同构**:大写关键字、`SELECT` 后每列独占一行并 **4 空格缩进**、表用短别名、`FROM`/`JOIN`/`WHERE`/`GROUP BY`/`ORDER BY` 分段清晰,`WHERE` 续行以 **`AND`** 开头;聚合/展示列需要 `AS` 时一律 **PascalCase 英文别名**(如 `BrokerName`、`TotalUnsettledAmount`)。
- **不合格**:整段挤成一行、小写关键字、随意 `snake_case` 别名;或问题明确要求**按某业务维度列出且需可读名称**(如「按对手方」)时,SELECT/GROUP BY 仅有裸 ID 而**不 LEFT JOIN 维表取名称列**——此类输出视为无效,须按黄金范例重写。
**硬性约束(必须遵守)**:
1. **合理推断业务语义**:用户问题中的时间范围(如"2024年1月")、状态含义(如"活跃"对应Active)、常见业务默认值(如"当前"指近期),应根据Schema中的字段注释和常见业务逻辑进行合理推断并转化为WHERE条件;但禁止编造问题中未提及的过滤维度或指标。
2. **禁止虚构值与占位符**:不得使用 `'[日期]'`、`TODO`、`xxx`、空泛占位等冒充具体字面量。若用户未给出具体日期、代码或 ID,应根据问题上下文推断合理值(如"2024年1月" → `ValueDate >= '2024-01-01' AND ValueDate < '2024-02-01'`),或使用Schema中常见的枚举值(如状态字段的`A/D/X`),**不要**留空或写占位符。
3. **输出版式与别名风格(统一规范)**:除遵守目标方言语法外,SQL **排版与命名**须与下方「标准版式范例」一致:
- **关键字**:`SELECT`、`FROM`、`JOIN`/`LEFT JOIN`、`ON`、`WHERE`、`AND`、`GROUP BY`、`ORDER BY`、`HAVING` 等使用**大写**。
- **换行与缩进**:`SELECT` 后换行;每个输出列**独占一行**,行首 **4 个空格**,列表达式之间用**行尾逗号**分隔(最后一列无逗号)。
- **`FROM` / `JOIN`**:主表与关联表各占一行;每张表使用**简短单字母或缩写别名**(如 `b`、`m`);`LEFT JOIN ... ON ...` 写全。
- **`WHERE`**:第一行写 `WHERE` 与首个条件;后续条件**每行一条**,行首两个空格后以 **`AND`** 开头续写(与范例一致)。
- **`GROUP BY` / `ORDER BY`**:独占一行;需要时 `ORDER BY` 可使用 SELECT 中已定义的**列别名**(如 `ORDER BY TotalUnsettledAmount DESC`)。
- **列别名**:表名、列名必须与 Schema **完全一致**(英文标识符)。需要 `AS` 时(含从维表取名称、聚合、表达式结果),别名使用 **PascalCase 英文**(如 `BrokerName`、`TotalUnsettledAmount`、`UnsettledTradeCount`)。若 Schema 中确有该键列,可写 `b.BrokerID` 等,可不强制 `AS`。
- **方言(T-SQL)**:字符串用 `+` 拼接;「今日」用 `CAST(GETDATE() AS DATE)`;标识符冲突用方括号 `[]`;非关键字尽量不加引号。不要用 MySQL 反引号或 `CURDATE()`。
4. **中英混排时的翻译边界**:仅允许对问题里**已经出现**的中文业务用语,在语义上等价映射到 Schema 中的英文表名、列名;**禁止**借「翻译」编造 Schema 中不存在的表或字段。
5. **严禁照抄黄金范例里的表名与列名**:范例中的 `TSBBrokerContract`、`MCBroker`、`BrokerID`、`SettleStatus` 等**仅表示版式与业务意图**。**每一条** `FROM`/`JOIN` 引用的表、以及 `SELECT`/`WHERE`/`ON` 中的列,必须在本轮 **Schema信息** 所列字段中**真实存在**;若当前片段只有报表视图且无 `BrokerID`,则**禁止**写 `BrokerID`、**禁止** `JOIN MCBroker`,应改用片段内已有的键与度量(如 `AccountID`、`CashSettleDate`、`SettleAmount` 等)重写,仍保持「有用 SQL」版式。
**原则**:
1. 只输出SQL语句,不要解释、注释或其他内容(除非SQL内注释)
2. 使用 **T-SQL(SQL Server)** 语法(与标准 SQL 交集部分按 T-SQL 实现)
3. 正确处理NULL值(使用IS NULL/IS NOT NULL,而非= NULL)
4. 聚合查询必须正确使用GROUP BY
5. 多表JOIN要明确ON条件(基于外键关系)
6. 避免SELECT *,明确列出所需字段
**金融/证券业务特殊注意**:
- 金额字段通常为DECIMAL类型,注意精度
- 日期字段常见:ValueDate(价值日期)、TradeDate(交易日期)、BusinessDate(业务日期)
- 状态字段:State(A=Active, D=Deleted, X=SameDayDeleted);SettleStatus(U=Unsettled未结算, S=Settled已结算)等,请参考Schema字段注释中的枚举说明
- 币种字段:CurrencyID,多币种查询需注意
- 负债/负数含义:许多余额字段负值表示负债(如LoanBalance)
**常见时间/状态推断指南**(需结合Schema字段注释):
- "2024年1月" → `WHERE date_col >= '2024-01-01' AND date_col < '2024-02-01'`
- "今天" / "当日" → `WHERE date_col >= CAST(GETDATE() AS DATE) AND date_col < DATEADD(DAY,1,CAST(GETDATE() AS DATE))`
- "最近N天" → `WHERE date_col >= DATEADD(DAY, -N, CAST(GETDATE() AS DATE))`
- "活跃" → 通常对应 `State = 'A'`(需确认Schema注释)
- "未结算" → 通常对应 `SettleStatus = 'U'` 或 `Settled = 0`
- "已删除" → 通常对应 `State = 'D'`
**重要**:以上推断需结合当前Schema中对应字段的实际注释进行调整;若Schema字段注释明确给出了枚举值映射,必须按注释执行。
**输出格式**:纯SQL字符串,或JSON格式:{"sql": "...", "explanation": "..."}
---
**业务级黄金范例(中文问题 ↔ 有用 SQL,版式即标准答案)**:
用户问题(示例):按对手方列出截至 2026-04-02 的所有未结算交易。
(日期规则:用户问题里**已写出具体日期**时,在 WHERE 中写入相同字面量,例如 `CashSettleDate <= '2026-04-02'`;**未给出具体日期**但包含时间范围描述(如"2024年1月")时,应合理推断为日期区间,例如 `OrderDate >= '2024-01-01' AND OrderDate < '2024-02-01'`,禁止使用 `'[日期]'` 等占位符。)
SQL(表名、字段名须与当前 Schema 一致;**以下版式、别名、JOIN/WHERE/GROUP BY/ORDER BY 结构为强制模板**):
SELECT
b.BrokerID,
m.Name AS BrokerName,
COUNT(*) AS UnsettledTradeCount,
SUM(b.SettleQuantity) AS TotalUnsettledQty,
SUM(b.SettleAmount) AS TotalUnsettledAmount,
MIN(b.BuySell) + '~' + MAX(b.BuySell) AS BuySellRange,
MIN(b.CashSettleDate) AS EarliestSettleDate,
MAX(b.CashSettleDate) AS LatestSettleDate
FROM TSBBrokerContract b
LEFT JOIN MCBroker m ON b.BrokerID = m.BrokerID
WHERE b.SettleStatus = 'U'
AND b.CashSettleDate <= '2026-04-02'
GROUP BY b.BrokerID, m.Name
ORDER BY TotalUnsettledAmount DESC;
(说明:`TSBBrokerContract`/`MCBroker`/`BrokerID`/`SettleStatus` 等为**演示用**名称;**禁止**在 Schema 未包含这些对象时照抄。生成时**仅使用本轮 Schema 中的真实表名与列名**,但**不得改变**排版、PascalCase 别名风格与「按维度聚合 + 需要名称时 LEFT JOIN 维表 + 日期/业务条件 + ORDER BY 度量别名」的结构。字符串拼接一律用 T-SQL 的 `+`。)
---
**示例(版式与范例一致)**:
示例1 - 单表查询:
问题:查询账户ID为'ACC001'的账户余额
Schema: MCAccount(AccountID, Name, AvailableBalance, MarketValue, MarginValue)
SQL:
SELECT
AccountID,
Name AS AccountName,
AvailableBalance,
MarketValue,
MarginValue
FROM MCAccount
WHERE AccountID = 'ACC001';
示例2 - 多表 INNER JOIN:
问题:查询账户'ACC001'持有的所有股票及数量
Schema: MCAccount(AccountID), MCAccountInstrument(AccountID, MarketID, InstrumentID, Settled)
SQL:
SELECT
a.AccountID,
i.MarketID,
i.InstrumentID AS InstrumentCode,
i.Settled AS HoldingQty
FROM MCAccount a
JOIN MCAccountInstrument i ON a.AccountID = i.AccountID
WHERE a.AccountID = 'ACC001';
示例3 - 时间范围推断(关键!):
问题:查询2024年1月的总销售额
Schema: Sales(OrderID, OrderDate, Amount, ProductID)
SQL:
SELECT
SUM(Amount) AS TotalSales,
COUNT(DISTINCT OrderID) AS OrderCount
FROM Sales
WHERE OrderDate >= '2024-01-01'
AND OrderDate < '2024-02-01';
示例4 - 状态推断(关键!):
问题:统计所有活跃账户的数量
Schema: MCAccount(AccountID, State, OpenDate) -- State说明: A=Active, D=Deleted, X=SameDayDeleted
SQL:
SELECT
COUNT(*) AS ActiveAccountCount
FROM MCAccount
WHERE State = 'A';
示例5 - 聚合 + 排序:
问题:按市场统计现金余额总额,从高到低排序
Schema: BCAccountMarketCash(AccountID, MarketID, Settled, UnderdueBuy, DueBuy)
SQL:
SELECT
MarketID,
SUM(Settled) AS TotalSettled,
SUM(UnderdueBuy) AS TotalUnderdueBuy,
SUM(DueBuy) AS TotalDueBuy
FROM BCAccountMarketCash
GROUP BY MarketID
ORDER BY TotalSettled DESC;
示例6 - 日期"今天"的处理:
问题:查询今天的交易记录
Schema: Ledger(TransactionID, TradeDate, Amount, AccountID)
SQL:
SELECT
TransactionID,
TradeDate,
Amount,
AccountID
FROM Ledger
WHERE TradeDate >= CAST(GETDATE() AS DATE)
AND TradeDate < DATEADD(DAY, 1, CAST(GETDATE() AS DATE));
示例7 - LEFT JOIN取名称(按维度展示可读名称):
问题:按产品类别统计销售额
Schema: Sales(ProductID, Amount, SaleDate), Product(ProductID, ProductName, CategoryName)
SQL:
SELECT
p.CategoryName,
SUM(s.Amount) AS TotalSales
FROM Sales s
LEFT JOIN Product p ON s.ProductID = p.ProductID
GROUP BY p.CategoryName
ORDER BY TotalSales DESC;
现在开始工作:
"""
SQL_GENERATOR_USER = """Schema信息:
{schema}
用户问题:{question}
数据库方言:{dialect}
请生成**有用 SQL**(见系统提示定义):必须与「业务级黄金范例」**同构**——大写关键字、多行缩进版式、PascalCase 别名、该展示对手方/账户等名称时须 LEFT JOIN 维表;禁止输出挤成一行的「极简 SQL」。"""
# ========== Validator Agent Prompt ==========
VALIDATOR_SYSTEM = """你是一个严谨的SQL审核员,负责验证SQL语句的正确性和安全性。
**验证清单**:
1. ✓ 语法正确(能够被SQL解析器解析)
2. ✓ 所有表名存在于提供的Schema中
3. ✓ 所有字段名属于对应的表(检查表.字段格式)
4. ✓ JOIN条件完整(每个JOIN都有ON条件,ON条件字段存在且类型兼容)
5. ✓ 聚合查询(GROUP BY)包含所有非聚合SELECT字段,或有合理的函数包裹
6. ✓ WHERE条件合理(没有明显逻辑错误)
7. ✓ HAVING子句只在聚合查询中使用
8. ✓ 排序字段存在
9. ✓ 无危险操作(DROP/DELETE/UPDATE/INSERT/ALTER/TRUNCATE等,除非明确允许)
10. ✓ 无明显性能问题(如全表扫描无WHERE、过度JOIN等)
**输出格式**(严格JSON):
{
"valid": true/false,
"errors": ["具体错误1", "具体错误2"],
"warnings": ["警告信息1"],
"suggestions": ["优化建议1"]
}
**错误类型说明**:
- "syntax_error": SQL语法错误
- "unknown_table": 表名不存在
- "unknown_column": 字段名不存在
- "missing_join_condition": JOIN缺少ON条件
- "missing_group_by": 聚合查询缺少GROUP BY
- "dangerous_operation": 危险操作
---
现在开始验证:
"""
VALIDATOR_USER = """需要验证的SQL:
{sql}
对应的Schema:
{schema}
请输出验证结果JSON:"""
# ========== Few-Shot 示例 ==========
FEW_SHOT_EXAMPLES: Dict[str, str] = {
"single_table": """
示例:单表查询
问题:查询所有状态为Active的账户数量
Schema: MCAccount(AccountID, State, OpenDate)
SQL:
SELECT
COUNT(*) AS ActiveAccountCount
FROM MCAccount
WHERE State = 'A';
""",
"join_query": """
示例:多表JOIN
问题:查询账户'ACC001'的持仓信息(包括股票代码、数量、成本)
Schema: MCAccount(AccountID), MCAccountInstrument(AccountID, MarketID, InstrumentID, Settled), HCInstrumentClosingPrice(MarketID, InstrumentID, ClosingPrice)
SQL:
SELECT
i.InstrumentID AS InstrumentCode,
i.Settled AS HoldingQty,
p.ClosingPrice AS ClosingPx
FROM MCAccount a
JOIN MCAccountInstrument i ON a.AccountID = i.AccountID
JOIN HCInstrumentClosingPrice p ON i.MarketID = p.MarketID AND i.InstrumentID = p.InstrumentID
WHERE a.AccountID = 'ACC001';
""",
"aggregation": """
示例:聚合统计
问题:统计每个市场的现金余额总额
Schema: BCAccountMarketCash(AccountID, MarketID, Settled, UnderdueBuy, DueBuy)
SQL:
SELECT
MarketID,
SUM(Settled) AS TotalSettled,
SUM(UnderdueBuy) AS TotalUnderdueBuy,
SUM(DueBuy) AS TotalDueBuy
FROM BCAccountMarketCash
GROUP BY MarketID;
""",
"date_filter": """
示例:日期筛选
问题:查询2024年1月有交易的账户
Schema: HCLedgerBalance(ValueDate, LedgerID, Amount), CompanyBusinessDate(BusinessDate)
SQL:
SELECT DISTINCT
LedgerID AS LedgerKey
FROM HCLedgerBalance
WHERE ValueDate >= '2024-01-01'
AND ValueDate < '2024-02-01';
""",
}
+48
View File
@@ -0,0 +1,48 @@
"""
配置管理模块
"""
from pydantic_settings import BaseSettings
from typing import Optional, List
class Settings(BaseSettings):
"""应用程序配置"""
# DeepSeek配置
deepseek_api_key: str
deepseek_base_url: str = "https://api.deepseek.com"
model_primary: str = "deepseek-chat"
temperature: float = 0.3
max_tokens: int = 4096
# Embedding配置
embedding_model_path: str = "./data/models/Qwen3-Embedding-0.6B"
vector_dim: int = 2048
use_local_embedding: bool = True
# Schema配置
schema_dir: str = "./data/schemas"
schema_file: Optional[str] = None # 特定schema文件路径
vector_db_path: str = "./data/embeddings/chroma"
# 验证配置
enable_sql_validation: bool = True
block_dangerous_sql: bool = True
dangerous_keywords: List[str] = ["DROP", "DELETE", "UPDATE", "INSERT", "ALTER", "TRUNCATE"]
# 重试配置
max_retry: int = 2
retry_delay: float = 1.0
# 日志配置
log_level: str = "INFO"
log_file: Optional[str] = None
class Config:
env_file = ".env"
case_sensitive = False
# 全局配置实例
settings = Settings()
File diff suppressed because it is too large Load Diff
Binary file not shown.
+20
View File
@@ -0,0 +1,20 @@
# Text2SQL 经验数据集
**来源**: `Example_text2sql.md`
**样本数**: 50
**生成时间**: 2026-04-10 14:51:56
## 文件说明
- `all_samples.jsonl` - 所有样本(JSONL格式)
- `difficulty_*.jsonl` - 按难度分类
- `by_tag/` - 按标签分类(每个标签一个文件)
- `fewshot_examples.md` - Few-shot示例(Markdown格式)
- `high_rating_samples.jsonl` - 高评分样本(rating≥8)
## 使用建议
1. **Few-shot prompting**: 使用 `fewshot_examples.md` 中的示例
2. **训练数据**: 使用 `all_samples.jsonl` 进行模型微调
3. **评估测试**: 使用 `high_rating_samples.jsonl` 作为测试集
4. **领域适应**: 按标签选择相关示例(如broker相关查询)
Binary file not shown.
+50
View File
@@ -0,0 +1,50 @@
{"qid": "Q1", "question_zh": "按对手方列出截至[日期]的所有未结算交易。", "sql": "-- 按对手方统计截至 2026-04-02 的未结算交易\n-- 使用 TSBBrokerContract(经纪商合约表),按 BrokerID(对手方经纪商)分组\n-- SettleStatus='U' 表示未结算;CashSettleDate <= '2026-04-02' 筛选截至日\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n COUNT(*) AS UnsettledTradeCount,\n SUM(b.SettleQuantity) AS TotalUnsettledQty,\n SUM(b.SettleAmount) AS TotalUnsettledAmount,\n MIN(b.BuySell) + '~' + MAX(b.BuySell) AS BuySellRange,\n MIN(b.CashSettleDate) AS EarliestSettleDate,\n MAX(b.CashSettleDate) AS LatestSettleDate\nFROM TSBBrokerContract b\nLEFT JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.SettleStatus = 'U'\n AND b.CashSettleDate <= '2026-04-02'\nGROUP BY b.BrokerID, m.Name\nORDER BY TotalUnsettledAmount DESC;", "schema_info": {"tables": {"TSBBrokerContract": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "LEFT", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `TSBBrokerContract` 是经纪商/对手方合约表,记录与外部对手方的交易合约,`BrokerID` 即对手方标识\n- `SettleStatus = 'U'` 表示未结算;`CashSettleDate <= '2026-04-02'` 筛选截至日未结清的合约\n- 关联 `MCBroker` 获取对手方经纪商名称\n- 按 `BrokerID` 分组汇总未结算数量和金额", "question_en": "Show all unsettled trades as of [date] grouped by counterparty.", "rating": 9, "execution_result": null, "result_note": "| BrokerID | BrokerName | UnsettledTradeCount | TotalUnsettledQty | TotalUnsettledAmount | BuySellRange | EarliestSettleDate | LatestSettleDate |\n|----------|-----------|---------------------|-------------------|---------------------|--------------|---------------------|-------------------|\n| CCASS | CCASS | 622 | 40,459,253 | 44,173,571.06 | B~S | 2025-07-30 | 2026-04-02 |\n\n> **注**:CCASS(Hong Kong Securities Clearing Company Limited)是香港交易所的中央结算机构,作为交易所交易的核心对手方。622笔未结算合约均为 HKEX 市场。", "tags": ["join", "ordering", "broker", "filter", "trade", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q2", "question_zh": "列出今日所有客户账户之间的股票转移记录。", "sql": "-- 查询今日客户账户间股票转移(参考日期:2026-04-02)\n-- 使用 TSBAccountInstrumentMovement,MovementType='T' 表示账户间转移\n-- ValueDate 为转移生效日期,关联 MCInstrument 获取证券名称\nSELECT \n m.MovementID,\n m.AccountID AS FromAccountID,\n m.TransferToAccountID,\n m.InstrumentID,\n i.Name AS InstrumentSymbol,\n m.MovementType,\n m.Quantity AS TransferQuantity,\n m.ValueDate AS TransferDate\nFROM TSBAccountInstrumentMovement m\nLEFT JOIN MCInstrument i ON m.InstrumentID = i.InstrumentID\nWHERE m.MovementType = 'T'\n AND m.ValueDate = '2026-04-02'\nORDER BY m.ValueDate;", "schema_info": {"tables": {"TSBAccountInstrumentMovement": {"alias": "m", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "LEFT", "on": "m.InstrumentID = i.InstrumentID"}]}, "explanation": "- `TSBAccountInstrumentMovement` 是持仓变动流水表,记录所有证券变动事件\n- `MovementType = 'T'`(Transfer)特指**账户间股票转移**,对应 `TransferToAccountID` 记录目标账户\n- `ValueDate` 是转移生效日期,可按日期过滤\n- 关联 `MCInstrument` 获取证券代码/名称\n- 注意:`BCAccountInstrument` 的 `TodayIn/TodayOut` 是**实时快照**,不带历史日期维度,不能用于查历史转移", "question_en": "List all stock transfers between client accounts performed today.", "rating": 9, "execution_result": null, "result_note": "当前查询无结果(测试环境中 `TSBAccountInstrumentMovement` 的 `MovementType='T'` 最新记录为 2025-10-21,无 2026-04-02 的账户间转移数据)", "tags": ["join", "ordering", "filter", "account", "left_join"], "difficulty": "hard"}
{"qid": "Q3", "question_zh": "今日结算使用的汇率是多少?", "sql": "-- 查询汇率类型列表 (固定日期: 2026-04-02)\nSELECT \n ExchangeRateID, \n Name, \n NameEx\nFROM HCExchangeRate\nWHERE ValueDate = '2026-04-02'\nORDER BY ExchangeRateID;", "schema_info": {"tables": {"HCExchangeRate": {"alias": "HCExchangeRate", "columns": []}}, "joins": []}, "explanation": "- `HCExchangeRate` 存储汇率类型定义\n- `HCExchangeRateDetail` 存储各货币对的汇率值\n- 两个表通过 `ExchangeRateID` + `ValueDate` 关联\n- `ExchangeRateDirection` = 'D' 表示直接汇率", "question_en": "What are the currency exchange rates used for today's settlement?", "rating": 9, "execution_result": null, "result_note": "", "tags": ["exchange_rate", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q4", "question_zh": "哪些券商尚有未履行的交收义务?", "sql": "-- 查询有未履行交收义务的经纪商(截至 2026-04-02)\n-- Settled < 0 表示经纪商欠我们的现金(未履行交收义务)\n-- 注意:BCBrokerCash.Settled 是经纪商在我们账户的已结算现金余额,负数=经纪商欠款\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n b.CurrencyID,\n b.Settled AS OwedToUsAmount,\n ABS(b.Settled) AS OutstandingAmount\nFROM BCBrokerCash b\nINNER JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.Settled < 0\nORDER BY ABS(b.Settled) DESC;", "schema_info": {"tables": {"BCBrokerCash": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `BCBrokerCash` 记录经纪商在我们账户的结算现金,`Settled < 0` = 经纪商欠我们(未履行交收义务)\n- 关联 `MCBroker` 获取经纪商名称\n- 按欠款金额降序排列,优先处理大额欠款", "question_en": "Which brokers have outstanding delivery obligations to us?", "rating": 8, "execution_result": null, "result_note": "| BrokerID | BrokerName | CurrencyID | OwedToUsAmount | OutstandingAmount |\n|----------|-----------|------------|-----------------|-------------------|\n| CCASS | CCASS | CNY | -52,680.00 | 52,680.00 |\n| CCASS | CCASS | USD | -90.00 | 90.00 |\n\n> 注:CCASS 欠我们的结算现金(CNY 52,680 + USD 90)。HKD 余额为正(+4,202,811.87)表示我们欠 CCASS,不属于\"未履行交收义务\"范畴。", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q5", "question_zh": "列出今日发出的所有追收保证金通知及其回复状态。", "sql": "-- 查询今日追缴保证金记录 (参考日期: 2026-04-02)\n-- 使用 MCAccount 的账户级追缴字段(CallForDepositDate = 追缴通知发出日期)\n-- 注意:HCAccountMarginCallForDeposit 是追缴每日快照表,不含\"通知发出日\"字段\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n a.CallForDeposit AS CallAmount,\n a.CallForDepositDate AS IssueDate,\n a.CallForDepositDays AS OverdueDays\nFROM MCAccount a\nWHERE a.CallForDepositDate = '2026-04-02'\nORDER BY a.CallForDeposit DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.CallForDepositDate` = 追缴通知发出日期,`CallForDeposit` = 追缴金额\n- `CallForDeposit < 0` 表示已结清;如查活跃追缴,应筛选 `CallForDeposit > 0`\n- `HCAccountMarginCallForDeposit` 是追缴每日历史快照,不适合查询\"今日发出的通知\"\n- `CallStatus` 字段在 `HCAccountMarginCallForDeposit` 中不存在", "question_en": "Show all margin calls issued today and their response status.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果(测试环境中 MCAccount 的 `CallForDepositDate` 最新到 2025-10-31,2026-04-02 无追缴通知记录)\n\n> 注:`MCAccount.CallForDeposit` 当前所有值均为负数(已结清的追缴金额),无活跃追缴记录。", "tags": ["margin", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q6", "question_zh": "所有货币的客户现金总余额是多少?", "sql": "-- 按货币统计客户现金余额\nSELECT \n CurrencyID,\n COUNT(DISTINCT AccountID) AS AccountCount,\n SUM(Settled) AS TotalSettledBalance,\n SUM(AccruedCreditInterest) AS TotalCreditInterest,\n SUM(AccruedDebitInterest) AS TotalDebitInterest,\n SUM(Settled) + SUM(AccruedCreditInterest) - SUM(AccruedDebitInterest) AS NetBalance\nFROM BCAccountCash\nGROUP BY CurrencyID\nORDER BY NetBalance DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `BCAccountCash` 记录账户现金余额\n- `Settled` 已结算余额\n- `AccruedCreditInterest` 应计存款利息\n- `AccruedDebitInterest` 应计借款利息", "question_en": "What is the total client cash balance across all currencies?", "rating": 9, "execution_result": null, "result_note": "| CurrencyID | AccountCount | TotalSettledBalance | NetBalance |\n|------------|-------------|--------------------|------------|\n| HKD | 2,906 | 52,195,305.77 | 52,195,305.77 |\n| TWD | 2 | -27,676.60 | -27,676.60 |\n| USD | 175 | 0 | 0 |\n| CNY | 95 | 0 | 0 |\n| GBP | 1 | 0 | 0 |", "tags": ["ordering", "account", "cash", "aggregation"], "difficulty": "medium"}
{"qid": "Q7", "question_zh": "今日结算后现金余额为负的账户列表。", "sql": "-- 查询现金余额为负的账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.Settled AS CashBalance,\n c.UnderdueCheque,\n c.BankAvailableBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.Settled < 0\nORDER BY c.Settled ASC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash.Settled` 表示已结算现金余额\n- 负数表示账户透支\n- 关联 `MCAccount` 获取账户名称", "question_en": "List accounts with negative cash balance after today's settlement.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | CurrencyID | CashBalance |\n|-----------|------------|------------|-------------|\n| M050009 | NG SUN SHU*** | HKD | -4,678,978.42 |\n| P050667 | WONG YIM HUNG | HKD | -780,196.94 |\n| M050521 | LO CHUN YIP | HKD | -290,487.54 |\n\n(共55个账户现金余额为负)", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q8", "question_zh": "明天生效的公司行动涉及哪些证券?", "sql": "-- 查询明日生效的公司行动 (固定日期: 2026-04-03)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.BalanceDate AS EffectiveDate,\n e.BalanceExDate AS ExDate,\n e.Remark AS Description\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE (e.BalanceDate = '2026-04-03' OR e.BalanceExDate = '2026-04-03')\n AND e.State = 'A';", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录权益分派信息\n- `BalanceDate` 权益登记日期\n- `BalanceExDate` 除权日期", "question_en": "Which instruments have corporate actions effective tomorrow?", "rating": 8, "execution_result": null, "result_note": "当前查询无结果(2026-04-03无公司行动)", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q9", "question_zh": "今日预计收到哪些股息?", "sql": "-- 查询今日预计收到的股息 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceDate AS PaymentDate,\n e.BalanceType,\n e.Remark AS DividendDetails\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.BalanceDate = '2026-04-02'\n AND e.BalanceType = 'C'\n AND e.State = 'A'\nORDER BY i.Name;", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录所有权益分派\n- `BalanceType = 'C'` 表示现金股息\n- `BalanceDate` 股息支付日期", "question_en": "What dividends are expected to be received today?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q10", "question_zh": "列出所有进行中IPO的待缴申购金额。", "sql": "-- 查询进行中IPO的待缴金额\nSELECT \n ip.InstrumentID,\n i.Name AS InstrumentName,\n i.State AS InstrumentStatus,\n ip.SubscriptionAmount,\n ip.SubscriptionPrice,\n ip.Quantity AS SubscriptionLot,\n ip.CreatedOn AS SubscriptionDate,\n ip.State AS SubscriptionStatus\nFROM MCInstrumentIPODetail ip\nINNER JOIN MCInstrument i ON ip.InstrumentID = i.InstrumentID\nWHERE ip.State = 'A'\n AND i.State = 'A'\nORDER BY ip.CreatedOn DESC;", "schema_info": {"tables": {"MCInstrumentIPODetail": {"alias": "ip", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "ip.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MCInstrumentIPODetail` 记录IPO认购详情\n- `SubscriptionAmount` 申购金额\n- `State = 'A'` 表示进行中", "question_en": "Show all pending subscription amounts for ongoing IPOs.", "rating": 8, "execution_result": null, "result_note": "| InstrumentID | InstrumentName | SubscriptionAmount | SubscriptionPrice | Quantity |\n|--------------|----------------|-------------------|-------------------|----------|\n| 02259 | HKEX | 7,231.19 | 36.16 | 100 |\n| 02259 | HKEX | 14,462.40 | 36.16 | 200 |\n\n> 注:MCInstrumentIPODetail 共 586 条进行中 IPO 记录(State='A'),以上为示例行。", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q11", "question_zh": "哪些客户尚未缴纳IPO申购款?", "sql": "-- 查询未缴纳IPO申购款的账户\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.TotalBoughtQuantity AS SubscriptionLot,\n bi.TotalBoughtConsideration AS SubscriptionAmount\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nINNER JOIN MCInstrumentIPODetail ip ON bi.InstrumentID = ip.InstrumentID\nWHERE ip.State = 'A'\n AND bi.TotalBoughtConsideration > 0\n AND bi.TotalBoughtFee = 0\nORDER BY bi.TotalBoughtConsideration DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}, "MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}, {"type": "INNER", "on": "bi.InstrumentID = ip.InstrumentID"}]}, "explanation": "- 通过比对买卖数量和手续费判断是否缴款\n- `TotalBoughtConsideration > 0` 有认购\n- `TotalBoughtFee = 0` 未支付手续费", "question_en": "Which clients have not yet paid their IPO subscription money?", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "ordering"], "difficulty": "hard"}
{"qid": "Q12", "question_zh": "本月累计的结算失败罚金是多少?", "sql": "-- 查询本月结算失败罚金 (2026年4月)\n-- 注意:BCAccountInstrument 无 FailedTradePenalty 字段,需另找结算罚金存储位置\n-- 目前未找到结算失败罚金字段,建议通过 TSBBrokerContract 或 BCBrokerCash 进一步排查\nSELECT \n COUNT(*) AS FailedTradeCount,\n MarketID\nFROM BCAccountInstrument\nWHERE YEAR(LastTransactionDate) = 2026\n AND MONTH(LastTransactionDate) = 4\nGROUP BY MarketID;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 无 `FailedTradePenalty` 字段,原始 SQL 会报错\n- `TSBBrokerContract` 或 `BCBrokerCash` 中可能存储结算相关费用,需进一步确认", "question_en": "What is the total failed trade penalty incurred this month?", "rating": 3, "execution_result": null, "result_note": "当前查询无结果(BCAccountInstrument 表无 FailedTradePenalty 字段,无法统计结算罚金)", "tags": ["filter", "aggregation"], "difficulty": "medium"}
{"qid": "Q13", "question_zh": "列出今日到期的所有股票借贷交易。", "sql": "-- 查询今日到期的股票借贷 (参考日期: 2026-04-02)\n-- MCMarket 表仅包含 HKEX/OSL/SETW,无独立借贷市场标识\n-- 股票借贷可能在持仓变动类型 HoldType 中标识,或在专门的 StockBorrowing 表中\n-- 此 SQL 按 DueBuy/DueSell 显示当前待交收证券,作为借贷合约的近似替代\nSELECT \n bi.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.DueBuy AS BorrowQuantity,\n bi.DueSell AS LoanQuantity,\n bi.DueBuy - bi.DueSell AS NetBorrow\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nWHERE bi.DueBuy > 0 OR bi.DueSell > 0;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}]}, "explanation": "- `DueBuy/DueSell` 表示待交收数量(借款买入/借出卖出),反映股票借贷待到期情况\n- `MCMarket` 表无 `MarketType='BORROW'` 标识,现有市场仅为 HKEX/OSL/SETW\n- 股票借贷详情可能存储在 `TSBAccountLoanContract` 或其他借贷专用表中,需业务确认", "question_en": "List all stock borrow/loan transactions due to settle today.", "rating": 5, "execution_result": null, "result_note": "当前查询无结果(BCAccountInstrument 中 DueBuy/DueSell 均为 0,无待交收证券)", "tags": ["join", "trade", "filter"], "difficulty": "medium"}
{"qid": "Q14", "question_zh": "列出已申请但尚未处理的客户提款请求。", "sql": "-- 查询待处理提款申请 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.TodayOut AS WithdrawalAmount,\n c.BankAvailableBalance AS AvailableBalance,\n c.State AS RecordStatus\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.TodayOut > 0\nORDER BY c.TodayOut DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `TodayOut` 今日计划支出\n- 待处理提款申请应体现在此字段", "question_en": "Show all client withdrawals requested but not yet processed.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q15", "question_zh": "本月应付给介绍经纪人的佣金返佣总额是多少?", "sql": "-- 查询本月应付返佣 (2026年4月)\n-- 注意:BCAccountInstrument 无 UpdatedAt 字段,用 LastTransactionDate 过滤本月有交易的账户\n-- 说明:TotalBoughtFee/TotalSoldFee 为历史累计字段,此处统计近期活跃账户的累计佣金供参考\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE YEAR(bi.LastTransactionDate) = 2026\n AND MONTH(bi.LastTransactionDate) = 4\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee + bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCRebateScheme` 可能存储返佣规则\n- 按AE汇总佣金", "question_en": "What is the total commission rebate payable to introducing brokers this month?", "rating": 6, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q16", "question_zh": "列出T+2交易缺少结算指令的账户。", "sql": "-- 查询T+2待交收但缺少指令的账户\n-- 注意:BCAccountInstrumentInstruction 表不存在,需改用 TSBSettlementInstruction\nSELECT \n bi.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.NextDayDueBuy AS T2DueBuy,\n bi.NextDayDueSell AS T2DueSell\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nWHERE (bi.NextDayDueBuy > 0 OR bi.NextDayDueSell > 0)\n AND NOT EXISTS (\n SELECT 1 FROM TSBSettlementInstruction si\n WHERE si.AccountOrBrokerID = bi.AccountID\n AND si.InstrumentID = bi.InstrumentID\n AND si.State IN ('P','A')\n );", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}, "TSBSettlementInstruction": {"alias": "si", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}]}, "explanation": "- `NextDayDueBuy/NextDayDueSell` T+2交收数量(次日到期)\n- `TSBSettlementInstruction` 是结算指令表,通过 `NOT EXISTS` 排除已有指令的记录\n- `BCAccountInstrumentInstruction` 表不存在,不能使用", "question_en": "Show accounts where settlement instruction is missing for T+2 trades.", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "trade"], "difficulty": "medium"}
{"qid": "Q17", "question_zh": "哪些客户已超过其信用额度?", "sql": "-- 查询超信用额度客户(使用 MarginLimit)\n-- 注意:MCAccount 无 CreditLimit 字段,应用 MarginLimit\nSELECT \n AccountID,\n Name AS AccountName,\n MarginLimit,\n MarketValue,\n MarginLimit - MarketValue AS AvailableCredit,\n CASE \n WHEN MarketValue > MarginLimit THEN '超额'\n WHEN MarketValue > MarginLimit * 0.8 THEN '接近限额'\n ELSE '正常'\n END AS Status\nFROM MCAccount\nWHERE MarginLimit > 0\n AND MarketValue > MarginLimit * 0.8\nORDER BY (MarketValue - MarginLimit) DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.MarginLimit` 保证金/信用限额(注意:无 `CreditLimit` 字段)\n- `MCAccount.MarketValue` 持仓市值\n- `MarginBLimit` 是单独借款限额,注意区分", "question_en": "Which clients have exceeded their credit limit?", "rating": 7, "execution_result": null, "result_note": "当前查询无超限客户", "tags": ["account", "limit", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q18", "question_zh": "今日收到的未清算支票总额是多少?", "sql": "-- 查询未清算支票 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.UnderdueCheque AS OverdueCheque,\n c.NextDayDueCheque AS PendingCheque,\n c.UnderdueCheque + c.NextDayDueCheque AS TotalUncleared\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE (c.UnderdueCheque > 0 OR c.NextDayDueCheque > 0) -- 注意:BCAccountCash 无这两个字段,需确认实际表\nORDER BY TotalUncleared DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash` 无 `UnderdueCheque` / `NextDayDueCheque` 字段,需业务确认支票数据存储位置", "question_en": "What is the total amount of uncleared cheques received today?", "rating": 4, "execution_result": null, "result_note": "当前查询无未清算支票", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q19", "question_zh": "列出今日起保证金比例发生变动的所有证券。", "sql": "-- 查询保证金比例变动的证券 (固定日期: 2026-04-02)\nSELECT \n i.InstrumentID,\n i.Name AS InstrumentName,\n i.MarginPercentage AS CurrentMarginRatio,\n i.MarginChangeDate\nFROM MCInstrument i\nWHERE i.MarginChangeDate = '2026-04-02'\nORDER BY i.MarginPercentage DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "i", "columns": []}}, "joins": []}, "explanation": "- `MCInstrument.MarginPercentage` 当前保证金比例\n- `MarginChangeDate` 变动日期", "question_en": "List all instruments with margin ratio changes effective today.", "rating": 7, "execution_result": null, "result_note": "当前查询无保证金比例变动记录", "tags": ["margin", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q20", "question_zh": "哪些公司行动的选择指令需在今日结束前提交?", "sql": "-- 查询今日截止的公司行动选择 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.ElectionPeriodTo AS Deadline,\n e.ElectionOptionFlag,\n e.Remark AS Description\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.ElectionPeriodTo = '2026-04-02'\n AND e.ElectionOptionFlag = 'Y'\n AND e.State = 'A';", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `ElectionPeriodTo` 选择截止日期\n- `ElectionOptionFlag = 'Y'` 需要选择", "question_en": "Which corporate action elections are due by end of day?", "rating": 8, "execution_result": null, "result_note": "当前查询无今日截止的选择", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q21", "question_zh": "截至昨日的客户借方余额应计利息是多少?", "sql": "-- 查询客户借方余额应计利息 (截至2026-04-01)\nSELECT \n SUM(AccruedDebitInterest) AS TotalDebitInterestAccrued,\n SUM(AccruedCreditInterest) AS TotalCreditInterestAccrued,\n SUM(AccruedDebitInterest) - SUM(AccruedCreditInterest) AS NetDebitInterest,\n COUNT(DISTINCT AccountID) AS AccountCount\nFROM BCAccountCash\nWHERE AccruedDebitInterest > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `AccruedDebitInterest` 借款应计利息\n- `AccruedCreditInterest` 存款应计利息", "question_en": "What is the interest accrued on client debit balances as of yesterday?", "rating": 8, "execution_result": null, "result_note": "| TotalDebitInterestAccrued | TotalCreditInterestAccrued | NetDebitInterest | AccountCount |\n|---------------------------|---------------------------|-----------------|-------------|\n| 2,022.70 | 464.15 | 1,558.55 | 55 |", "tags": ["filter", "account", "interest", "cash", "aggregation"], "difficulty": "hard"}
{"qid": "Q22", "question_zh": "列出今日所有公司账户与客户账户之间的现金划转。", "sql": "-- 查询公司账户与客户账户现金划转 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n a.AccountType,\n c.CurrencyID,\n c.TodayIn AS CashInflow,\n c.TodayOut AS CashOutflow,\n c.Settled AS CurrentBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE (c.TodayIn > 0 OR c.TodayOut > 0)\nORDER BY c.TodayIn + c.TodayOut DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- 公司账户与客户账户通过 `AccountType` 区分\n- `TodayIn/TodayOut` 记录现金流动", "question_en": "List all cash movements between house and client accounts today.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q23", "question_zh": "列出所有逾期未付保证金利息的账户。", "sql": "-- 查询逾期保证金利息账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.LoanInterestMarginOverdue AS MarginOverdueInterest,\n c.LoanInterestMarginBOverdue AS MarginBOverdueInterest,\n c.LoanInterestOverdue AS GeneralOverdueInterest\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.LoanInterestMarginOverdue > 0 \n OR c.LoanInterestMarginBOverdue > 0\n OR c.LoanInterestOverdue > 0\nORDER BY (c.LoanInterestMarginOverdue + c.LoanInterestMarginBOverdue + c.LoanInterestOverdue) DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `LoanInterestMarginOverdue` 保证金账户逾期利息\n- `LoanInterestMarginBOverdue` B类保证金逾期利息", "question_en": "Show all accounts with overdue margin interest payments.", "rating": 8, "execution_result": null, "result_note": "当前查询无逾期利息记录", "tags": ["join", "ordering", "margin", "filter", "account", "interest"], "difficulty": "hard"}
{"qid": "Q24", "question_zh": "有多少客户报表已生成成功但尚未发送?", "sql": "-- 查询已生成但未发送的报表\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n a.LastDailyStatementDate,\n a.LastMonthlyStatementDate,\n a.LastStatementGenerateTime,\n a.LastStatementSendTime,\n CASE \n WHEN a.LastStatementGenerateTime > a.LastStatementSendTime THEN '未发送'\n ELSE '已发送'\n END AS DeliveryStatus\nFROM MCAccount a\nWHERE a.LastStatementGenerateTime IS NOT NULL\n AND (a.LastStatementSendTime IS NULL \n OR a.LastStatementGenerateTime > a.LastStatementSendTime)\nORDER BY a.LastStatementGenerateTime DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `LastStatementGenerateTime` 报表生成时间\n- `LastStatementSendTime` 报表发送时间", "question_en": "How many client statements were successfully generated but not yet delivered?", "rating": 7, "execution_result": null, "result_note": "当前查询无未发送报表", "tags": ["ordering", "account", "filter", "statement"], "difficulty": "easy"}
{"qid": "Q25", "question_zh": "列出所有待批准的股票转移请求。", "sql": "-- 查询待批准的股票转移\nSELECT \n AccountID,\n InstrumentID,\n MovementType,\n MovementQuantity,\n FromAccountID,\n ToAccountID,\n RequestDate,\n ApprovalStatus,\n RequestedBy\nFROM BCAccountInstrumentMovement\nWHERE ApprovalStatus = 'P'\nORDER BY RequestDate DESC;", "schema_info": {"tables": {"BCAccountInstrumentMovement": {"alias": "BCAccountInstrumentMovement", "columns": []}}, "joins": []}, "explanation": "- 股票转移请求存储在专用表中\n- `ApprovalStatus = 'P'` 待批准状态", "question_en": "Show all pending stock movement requests that require approval.", "rating": 6, "execution_result": null, "result_note": "当前查询无待批准请求", "tags": ["filter", "ordering"], "difficulty": "easy"}
{"qid": "Q26", "question_zh": "本月各交易所的结算费用明细如何?", "sql": "-- 按交易所统计结算费用 (2026年4月)\n-- 说明:BCAccountInstrument 表中 TotalBoughtFee/TotalSoldFee 是持仓级别的交易费用字段\n-- LastTransactionDate 表示该持仓最后交易日期\n-- 查询逻辑:筛选最后交易日期在本月内的持仓记录,按交易所汇总交易费用\nSELECT \n bi.MarketID,\n m.MarketName,\n SUM(bi.TotalBoughtFee) AS TotalBuyFee,\n SUM(bi.TotalSoldFee) AS TotalSellFee,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalSettlementFee,\n COUNT(DISTINCT bi.AccountID) AS TradingAccountCount\nFROM BCAccountInstrument bi\nINNER JOIN MCMarket m ON bi.MarketID = m.MarketID\nWHERE bi.LastTransactionDate >= '2026-04-01' AND bi.LastTransactionDate < '2026-05-01'\nGROUP BY bi.MarketID, m.MarketName\nORDER BY TotalSettlementFee DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCMarket": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.MarketID = m.MarketID"}]}, "explanation": "- `BCAccountInstrument` 存储持仓级别信息,包含各持仓的交易费用累计\n- `MCMarket` 存储市场信息,提供市场名称\n- `LastTransactionDate` 用于过滤本月有交易的持仓记录\n- 按市场分组汇总结算费用", "question_en": "What is the breakdown of settlement fees by exchange for this month?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "trade", "aggregation", "date_range"], "difficulty": "hard"}
{"qid": "Q27", "question_zh": "列出所有超过3天的暂记账户分录。", "sql": "-- 查询超过3天的暂记账户分录 (2026-04-02)\n-- 说明:TCAccountCashMovement 是现金流水表\n-- NeedHoldFlag='Y' 表示暂记分录\n-- Amount - ReleasedAmount 表示未释放金额(暂记余额)\n-- 筛选未释放且超过3天的暂记分录\nSELECT \n cm.AccountID,\n cm.MovementID,\n cm.ValueDate,\n cm.CurrencyID,\n cm.Amount - ISNULL(cm.ReleasedAmount, 0) AS PendingBalance,\n cm.Remark,\n DATEDIFF(DAY, cm.ValueDate, '2026-04-02') AS DaysOutstanding\nFROM TCAccountCashMovement cm\nWHERE cm.NeedHoldFlag = 'Y'\n AND cm.Amount - ISNULL(cm.ReleasedAmount, 0) != 0\n AND DATEDIFF(DAY, cm.ValueDate, '2026-04-02') > 3\nORDER BY DaysOutstanding DESC, PendingBalance DESC;", "schema_info": {"tables": {"TCAccountCashMovement": {"alias": "cm", "columns": []}}, "joins": []}, "explanation": "- `TCAccountCashMovement` 存储现金流水记录\n- `NeedHoldFlag = 'Y'` 标识暂记(待确认)分录\n- `Amount - ReleasedAmount` 计算未释放的暂记余额\n- `DATEDIFF` 计算距今天数\n- `DATEDIFF > 3` 筛选超过3天的记录", "question_en": "List all suspense account entries older than 3 days.", "rating": 9, "execution_result": null, "result_note": "**查询结果:0条记录**\n\n当前没有超过3天未释放的暂记账户分录。所有暂记分录的 ReleasedAmount = Amount,已全部释放。", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q28", "question_zh": "哪些客户已请求更改结算货币?", "sql": "-- 查询请求更改结算货币的客户\n-- 说明:经查 MCAccountCurrency 表无 CurrencyChangeStatus/RequestedCurrencyID 等字段\n-- 数据库中没有专门的货币变更请求表\n-- 此查询基于账户货币历史时间表(HCAccountCurrencyTimetable)展示货币生效安排\nSELECT \n act.AccountID,\n mca.Name AS AccountName,\n act.CurrencyID AS Currency,\n act.EffectiveDateFrom,\n act.EffectiveDateTo,\n act.AccountTypeID\nFROM HCAccountCurrencyTimetable act\nINNER JOIN MCAccount mca ON act.AccountID = mca.AccountID\nWHERE act.EffectiveDateTo IS NULL\nORDER BY act.EffectiveDateFrom DESC;", "schema_info": {"tables": {"HCAccountCurrencyTimetable": {"alias": "act", "columns": []}, "MCAccount": {"alias": "mca", "columns": []}}, "joins": [{"type": "INNER", "on": "act.AccountID = mca.AccountID"}]}, "explanation": "- `HCAccountCurrencyTimetable` 记录账户货币生效时间表\n- `EffectiveDateTo IS NULL` 表示当前生效的货币配置\n- 如需货币变更请求功能,建议在系统中扩展相关表结构", "question_en": "Which clients have requested a change in settlement currency?", "rating": 4, "execution_result": null, "result_note": "**说明:** 数据库中没有专门的货币变更请求表。`MCAccountCurrency` 表仅记录账户当前货币配置,无变更请求字段。", "tags": ["join", "account", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q29", "question_zh": "列出后台系统中所有活跃用户账户及其最后登录日期。", "sql": "-- 查询活跃用户及其登录情况\nSELECT \n u.UserID,\n u.Name AS UserName,\n u.Status,\n u.LogonEnableFlag,\n u.LastLogonTime,\n u.BranchID,\n CASE u.CompanyAEFlag WHEN 'Y' THEN '公司经纪' ELSE '个人' END AS AEType,\n CASE \n WHEN u.LastLogonTime >= DATEADD(DAY, -7, GETDATE()) THEN '近7天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -30, GETDATE()) THEN '近30天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -90, GETDATE()) THEN '近90天活跃'\n ELSE '长期未登录'\n END AS ActivityStatus\nFROM MCUser u\nWHERE u.State = 'A'\n AND u.LogonEnableFlag = 'Y'\nORDER BY u.LastLogonTime DESC;", "schema_info": {"tables": {"MCUser": {"alias": "u", "columns": []}}, "joins": []}, "explanation": "- `MCUser` 存储用户信息\n- `LastLogonTime` 最后登录时间", "question_en": "List all active user accounts in the back office system with last login date.", "rating": 9, "execution_result": null, "result_note": "| UserID | UserName | Status | LogonEnableFlag | LastLogonTime | ActivityStatus |\n|--------|----------|--------|-----------------|---------------|----------------|\n| SUPPORT | SUPPORT | N | Y | 2026-04-08 | 近7天活跃 |\n| ROSANNA | ROSANNA | N | Y | 2025-10-21 | 长期未登录 |\n| SING | WONG LO SING | N | Y | 2025-10-21 | 长期未登录 |\n| LEONNG | LEON NG | N | Y | 2025-10-21 | 长期未登录 |", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q30", "question_zh": "按结算日期划分的未结算交易总风险敞口是多少?", "sql": "-- 按结算日期分组的未结算交易敞口\nSELECT \n SettlementType,\n SUM(Amount) AS TotalExposure\nFROM (\n SELECT 'DueBuy_T1' AS SettlementType, SUM(DueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'DueSell_T1' AS SettlementType, SUM(DueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueBuy' AS SettlementType, SUM(NextDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueSell' AS SettlementType, SUM(NextDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueBuy' AS SettlementType, SUM(NextTwoDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueSell' AS SettlementType, SUM(NextTwoDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueBuy' AS SettlementType, SUM(TodayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueSell' AS SettlementType, SUM(TodayDueSell) AS Amount FROM BCAccountInstrument\n) t\nGROUP BY SettlementType\nORDER BY SettlementType;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表包含所有账户的证券持仓和交收信息\n- `DueBuy/DueSell` 表示T+1到期的买卖数量", "question_en": "What is the total exposure from unsettled trades by settlement date?", "rating": 8, "execution_result": null, "result_note": "| SettlementType | TotalExposure |\n|----------------|---------------|\n| DueBuy_T1 | 0 |\n| DueSell_T1 | 0 |\n| NextDayDueBuy | 0 |\n| NextDayDueSell | 0 |\n| NextTwoDayDueBuy | 0 |\n| NextTwoDayDueSell | 0 |\n| TodayDueBuy | 1,800 |\n| TodayDueSell | 1,000 |\n\n**注:** `DueBuy/DueSell` 等字段表示应交收数量(T+1/T+2/今日),非金额敞口。如需金额敞口,需乘以价格。", "tags": ["union", "trade", "ordering", "aggregation"], "difficulty": "hard"}
{"qid": "Q31", "question_zh": "指定日期或日期范围内收到的交易量(如成交金额)及相应佣金是多少?", "sql": "-- 交易量和佣金统计\nSELECT \n SUM(TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(TotalBoughtFee) AS TotalBuyCommission,\n SUM(TotalSoldConsideration) AS TotalSellConsideration,\n SUM(TotalSoldFee) AS TotalSellCommission,\n SUM(TotalBoughtConsideration) + SUM(TotalSoldConsideration) AS TotalConsideration,\n SUM(TotalBoughtFee) + SUM(TotalSoldFee) AS TotalCommission\nFROM BCAccountInstrument;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表记录了账户所有历史买卖交易\n- `TotalBoughtConsideration / TotalSoldConsideration`: 买卖成交金额", "question_en": "What is the trading volume (e.g., consideration) and corresponding commission amount received for a specific date or date range?", "rating": 9, "execution_result": null, "result_note": "| TotalBuyConsideration | TotalBuyCommission | TotalSellConsideration | TotalSellCommission | TotalConsideration | TotalCommission |\n|---------------------|-------------------|----------------------|--------------------|-------------------|-----------------|\n| 945,480,833.78 | 793,149.07 | 278,693,891.64 | 809,248.89 | 1,224,174,725.42 | 1,602,397.96 |", "tags": ["trade", "aggregation"], "difficulty": "easy"}
{"qid": "Q32", "question_zh": "各市场客户不同资产(如股票、债券、基金、虚拟资产)的总持仓是多少?", "sql": "-- 按市场统计客户持仓\nSELECT \n b.MarketID,\n COUNT(DISTINCT b.AccountID) AS AccountCount,\n SUM(b.Settled) AS TotalQuantity,\n SUM(b.CostAmount) AS TotalCostAmount,\n SUM(b.TotalBoughtQuantity) AS TotalBoughtQty,\n SUM(b.TotalSoldQuantity) AS TotalSoldQty\nFROM BCAccountInstrument b\nGROUP BY b.MarketID\nORDER BY TotalCostAmount DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "b", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表记录账户在各市场的持仓\n- `MarketID` 区分不同市场", "question_en": "What is the total client holding of different assets (e.g., stocks, bonds, funds, virtual assets) by each market?", "rating": 8, "execution_result": null, "result_note": "| MarketID | AccountCount | TotalQuantity | TotalCostAmount | TotalBoughtQty | TotalSoldQty |\n|----------|-------------|---------------|-----------------|---------------|-------------|\n| HKEX | 2,102 | 717,471,548 | 87,813,213.45 | 1,015,923,906 | 298,452,798 |\n| SETW | 2 | 3,100 | 32,298.50 | 4,100 | 1,000 |", "tags": ["account", "holding", "ordering", "aggregation"], "difficulty": "medium"}
{"qid": "Q33", "question_zh": "今日是否有追缴保证金通知?", "sql": "-- 查询今日追缴保证金记录 (固定日期: 2026-04-02)\nSELECT \n m.AccountID,\n a.Name AS AccountName,\n m.CallForDeposit,\n m.CallForDepositDate,\n m.CallForDepositDays\nFROM HCAccountMarginCallForDeposit m\nINNER JOIN MCAccount a ON m.AccountID = a.AccountID\nWHERE m.CallForDepositDate = '2026-04-02';", "schema_info": {"tables": {"HCAccountMarginCallForDeposit": {"alias": "m", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "m.AccountID = a.AccountID"}]}, "explanation": "- `HCAccountMarginCallForDeposit` 记录追缴保证金信息\n- `CallForDeposit` 追缴金额", "question_en": "Have there been any margin calls today?", "rating": 9, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "margin", "filter"], "difficulty": "easy"}
{"qid": "Q34", "question_zh": "保证金账户前20大持仓(按市值)是多少?", "sql": "-- 保证金账户按市值排序的前20持仓\nSELECT TOP 20\n a.AccountID,\n a.Name AS AccountName,\n a.MarketValue,\n a.MarginDebitRatio AS MarginDebitBalanceRatio,\n a.MarginPosition,\n a.CallForDeposit,\n a.MarginFacilityFlag\nFROM MCAccount a\nWHERE a.MarginFacilityFlag = 'Y'\n AND a.State = 'A'\n AND a.MarketValue > 0\nORDER BY a.MarketValue DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 表包含所有账户信息\n- `MarginFacilityFlag = 'Y'` 筛选保证金账户", "question_en": "What are the top 20 holdings (based on market value) for margin accounts?", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginPosition |\n|-----------|-------------|------------|----------------|\n| M050009 | NG SUN SHU*** | 57,420,000 | 35,515,021.58 |\n| M050013 | NG CHUNG WAI*** | 19,504,520 | 10,918,958.78 |\n| M050193 | WONG KING YIU*** ^ | 11,682,920 | 3,340,099.05 |\n| P020160 | LAW SHIU MING DENNIS | 7,520,370 | 0 |\n| P030078 | MAK SUI BING | 7,120,309.94 | 0 |\n| P051101 | CHUNG CHUNG YEE | 7,117,808.04 | 0 |\n| M050170 | FUNG LAI FONG ANNA | 7,009,227.25 | 4,136,857 |\n| P220005 | LAI KAM SUI # | 5,837,102.10 | 97.97 |\n| P280628 | CHAN KWOK MO # | 5,761,997.48 | 62,508.23 |\n| P280455 | LEUNG KA CHI # | 5,487,971.20 | -64,981.22 |\n\n(共20条记录,以上展示前10条)", "tags": ["ordering", "holding", "margin", "filter", "limit", "account"], "difficulty": "hard"}
{"qid": "Q35", "question_zh": "列出本月按客户主任分组的佣金总额,以及相应的成交金额和返佣金额。", "sql": "-- 按经纪商/客户主任分组的佣金统计\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee) AS TotalBuyCommission,\n SUM(bi.TotalSoldFee) AS TotalSellCommission,\n SUM(bi.TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(bi.TotalSoldConsideration) AS TotalSellConsideration,\n SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE a.State = 'A'\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCAccount.AEID` 关联经纪商/客户主任\n- `BCAccountInstrument` 包含交易费用数据", "question_en": "List the total commission received this month by AE, along with corresponding consideration and rebate amounts.", "rating": 8, "execution_result": null, "result_note": "| AEID | AEName | AccountCount | TotalBuyCommission | TotalSellCommission | TotalCommission |\n|------|--------|-------------|-------------------|--------------------|----------------|\n| C01 | CHAN YUET HUNG | 628 | 183,244.64 | 187,220.59 | 370,465.23 |\n| C28 | CHAN SHU SHAN | 405 | 179,275.89 | 176,760.39 | 356,036.28 |\n| C05 | CENTRAL | 517 | 97,368.51 | 102,819.88 | 200,188.39 |\n| C33 | LEON NG | 13 | 71,541.06 | 72,620.60 | 144,161.66 |\n| C07 | CHAN WING PAI | 75 | 73,255.68 | 69,115.58 | 142,371.26 |\n| C10 | TOKWAWAN / KOWLOON CITY | 369 | 51,059.78 | 57,288.86 | 108,348.64 |\n| C08 | WONG HON KONG | 380 | 47,505.15 | 46,300.39 | 93,805.54 |\n| C36 | Name Of C36 | 146 | 40,945.66 | 35,682.86 | 76,628.52 |\n| C66 | CHEUNG YUK LING IVA | 17 | 24,458.82 | 22,723.18 | 47,182.00 |\n| C19 | WONG LO SING | 60 | 13,337.69 | 13,912.30 | 27,249.99 |\n\n(共15个AE有佣金记录,以上展示前10条)\n\n**注:** 当前SQL无日期条件,统计所有历史累计佣金。如需\"本月\"佣金,需添加 `LastTransactionDate >= '2026-04-01'` 条件。", "tags": ["join", "ordering", "filter", "account", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q36", "question_zh": "各市场(如港股T+1和T+2、美股T+1)的待结算金额是多少?", "sql": "-- 按市场统计待结算金额\nSELECT \n MarketID,\n SUM(DueBuy + DueSell) AS TotalPendingQty,\n SUM(NextDayDueBuy + NextDayDueSell) AS T2TotalPendingQty\nFROM BCAccountInstrument\nWHERE DueBuy > 0 OR DueSell > 0 OR NextDayDueBuy > 0 OR NextDayDueSell > 0\nGROUP BY MarketID;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 记录各市场的待交收数量\n- `DueBuy/DueSell` 对应T+1交收", "question_en": "What is the pending settlement amount for each market (e.g., HK T+1 & T+2, US T+1)?", "rating": 7, "execution_result": null, "result_note": "| MarketID | TotalPendingQty | T2TotalPendingQty |\n|----------|----------------|------------------|\n| HKEX | 0 | 0 |\n| SETW | 0 | 0 |", "tags": ["filter", "aggregation"], "difficulty": "medium"}
{"qid": "Q37", "question_zh": "是否有正在进行的IPO事件,其认购状态如何?", "sql": "-- 查询进行中的IPO (2026年4月)\nSELECT \n i.InstrumentID,\n i.MarketID,\n i.Name AS InstrumentName,\n i.State AS InstrumentStatus,\n ip.Quantity AS SubscriptionLot,\n ip.SubscriptionAmount,\n ip.CreatedOn AS SubscriptionDate\nFROM MCInstrument i\nINNER JOIN MCInstrumentIPODetail ip ON i.InstrumentID = ip.InstrumentID\nWHERE YEAR(ip.CreatedOn) = 2026\n AND MONTH(ip.CreatedOn) = 4\nORDER BY ip.CreatedOn DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "i", "columns": []}, "MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": [{"type": "INNER", "on": "i.InstrumentID = ip.InstrumentID"}]}, "explanation": "- `MCInstrument` 表记录证券信息\n- `MCInstrumentIPODetail` 记录IPO认购详情", "question_en": "Are there any IPO events currently in progress, and what is their subscription status?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "filter", "ipo", "ordering"], "difficulty": "easy"}
{"qid": "Q38", "question_zh": "本月IPO事件的总佣金、手续费和保证金利息是多少?", "sql": "-- IPO相关费用汇总 (2026年4月)\nSELECT \n 'IPO Commission' AS FeeType,\n SUM(ip.SubscriptionAmount * 0.001) AS EstimatedFee\nFROM MCInstrumentIPODetail ip\nWHERE YEAR(ip.CreatedOn) = 2026\n AND MONTH(ip.CreatedOn) = 4;", "schema_info": {"tables": {"MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": []}, "explanation": "- IPO相关费用分散在多个表中\n- 需要关联 `BCAccountInstrument` 获取IPO交易费用", "question_en": "What are the total commission, handling fees, and margin interest for IPO events this month?", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["margin", "aggregation", "filter", "interest"], "difficulty": "easy"}
{"qid": "Q39", "question_zh": "列出今日需要执行的公司行动(如权益分派)。", "sql": "-- 查询今日生效的公司行动 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.MarketID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.BalanceDate,\n e.BalanceExDate,\n e.Remark,\n e.State\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.State = 'A'\n AND (\n e.BalanceDate = '2026-04-02'\n OR e.BalanceExDate = '2026-04-02'\n OR e.AutoHoldDate = '2026-04-02'\n OR e.AutoDeductDate = '2026-04-02'\n );", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录所有权益分派信息\n- `BalanceDate` 权益登记日期", "question_en": "List corporate actions (e.g., entitlements) that need to be performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q40", "question_zh": "列出今日执行的所有股票转移/移动。", "sql": "-- 今日股票转入/转出 (固定日期: 2026-04-02)\nSELECT \n AccountID,\n MarketID,\n InstrumentID,\n TodayIn AS QuantityIn,\n TodayOut AS QuantityOut,\n HoldForDeposit AS PendingDeposit,\n HoldForWithdrawal AS PendingWithdrawal\nFROM BCAccountInstrument\nWHERE TodayIn > 0 OR TodayOut > 0;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 记录股票持仓变动\n- `TodayIn` 今日转入数量", "question_en": "List all stock movements performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["filter"], "difficulty": "easy"}
{"qid": "Q41", "question_zh": "列出今日执行的所有现金划转。", "sql": "-- 今日现金变动汇总 (固定日期: 2026-04-02)\nSELECT \n b.AccountID,\n a.Name AS AccountName,\n b.TodayIn AS CashIn,\n b.TodayOut AS CashOut,\n b.BankAvailableBalance\nFROM BCAccountCash b\nINNER JOIN MCAccount a ON b.AccountID = a.AccountID\nWHERE b.TodayIn > 0 OR b.TodayOut > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "b", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "b.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash` 记录账户现金变动\n- `TodayIn` 今日现金流入", "question_en": "List all cash movements performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "filter", "cash"], "difficulty": "easy"}
{"qid": "Q42", "question_zh": "列出后台系统中的活跃用户。", "sql": "-- 查询后台系统活跃用户\nSELECT \n u.UserID,\n u.Name AS UserName,\n u.Status,\n u.LogonEnableFlag,\n u.LastLogonTime,\n u.BranchID,\n u.DepartmentID,\n CASE u.CompanyAEFlag WHEN 'Y' THEN '公司经纪' ELSE '个人' END AS AEType\nFROM MCUser u\nWHERE u.State = 'A'\n AND u.LogonEnableFlag = 'Y'\nORDER BY u.LastLogonTime DESC;", "schema_info": {"tables": {"MCUser": {"alias": "u", "columns": []}}, "joins": []}, "explanation": "- `MCUser` 存储系统用户信息\n- `State = 'A'` 用户状态正常", "question_en": "List active users in the back office.", "rating": 9, "execution_result": null, "result_note": "| UserID | UserName | Status | LogonEnableFlag | LastLogonTime | AEType |\n|--------|----------|--------|-----------------|---------------|--------|\n| SUPPORT | SUPPORT | N | Y | 2026-04-03 18:53:04 | 个人 |\n| ROSANNA | ROSANNA | N | Y | 2025-10-21 16:47:11 | 个人 |", "tags": ["filter", "ordering"], "difficulty": "easy"}
{"qid": "Q43", "question_zh": "列出持仓为负数(透支)的账户。", "sql": "-- 查询透支持仓账户\nSELECT \n AccountID,\n Name AS AccountName,\n MarketValue,\n AssetBalance,\n LiabilityBalance,\n MarginPosition,\n MarginFacilityFlag\nFROM MCAccount\nWHERE MarketValue < 0\n AND State = 'A'\nORDER BY MarketValue ASC;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MarketValue < 0` 筛选持仓为负的账户\n- 持仓为负通常表示账户存在透支或结算问题", "question_en": "List accounts with overdrawn positions.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginFacilityFlag |\n|-----------|-------------|-------------|-------------------|\n| P030012 | LAI YEE TAK HELEN | -112,196.60 | N |\n| P350022 | CHAN YAU KING*** | -92,950.00 | N |\n| P011212 | NG SIU PING | -12,352.00 | N |", "tags": ["account", "holding", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q44", "question_zh": "本月收到/支付的利息金额是多少(如客户借款利息和存款利息)?", "sql": "-- 本月利息收支汇总 (2026年4月)\nSELECT \n SUM(AccruedCreditInterest) AS CreditInterest,\n SUM(AccruedDebitInterest) AS DebitInterest,\n SUM(AccruedCreditInterest) - SUM(AccruedDebitInterest) AS NetInterest\nFROM BCAccountCash;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `BCAccountCash` 记录账户现金和利息信息\n- `AccruedCreditInterest` 应计存款利息", "question_en": "What is the interest amount received/paid this month (e.g., client debit interest and credit interest)?", "rating": 7, "execution_result": null, "result_note": "| CreditInterest | DebitInterest | NetInterest |\n|----------------|---------------|-------------|\n| 464.15 | 2,022.70 | -1,558.55 |", "tags": ["account", "aggregation", "interest"], "difficulty": "easy"}
{"qid": "Q45", "question_zh": "不同经纪商(如非中央结算系统持仓)的客户总持仓是多少?", "sql": "-- 按托管位置统计持仓(非CCASS)\nSELECT \n loc.LocationID,\n loc.Name AS LocationName,\n COUNT(DISTINCT bi.AccountID) AS AccountCount,\n SUM(bi.Settled) AS TotalQuantity,\n SUM(bi.CostAmount) AS TotalCostAmount\nFROM BCAccountLocationInstrument bi\nINNER JOIN MCLocation loc ON bi.LocationID = loc.LocationID\nWHERE loc.CCASSFlag = 'N'\nGROUP BY loc.LocationID, loc.Name\nORDER BY TotalQuantity DESC;", "schema_info": {"tables": {"BCAccountLocationInstrument": {"alias": "bi", "columns": []}, "MCLocation": {"alias": "loc", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.LocationID = loc.LocationID"}]}, "explanation": "- `BCAccountLocationInstrument` 记录按托管位置分类的持仓\n- `MCLocation` 存储托管位置信息", "question_en": "What is the total client holding at different broker firms (e.g., non-CCASS locations)?", "rating": 7, "execution_result": null, "result_note": "当前查询需要验证 Location 表关联", "tags": ["join", "ordering", "holding", "broker", "filter", "account", "aggregation"], "difficulty": "hard"}
{"qid": "Q46", "question_zh": "支付给其他经纪商的佣金是多少?", "sql": "-- 查询支付给其他经纪商的佣金\nSELECT \n b.BrokerID,\n b.Name AS BrokerName,\n SUM(bc.Commission) AS TotalCommission,\n SUM(bc.Consideration) AS TotalConsideration\nFROM MCBroker b\nINNER JOIN BCBrokerCash bc ON b.BrokerID = bc.BrokerID\nWHERE bc.Commission > 0\nGROUP BY b.BrokerID, b.Name\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCBroker": {"alias": "b", "columns": []}, "BCBrokerCash": {"alias": "bc", "columns": []}}, "joins": [{"type": "INNER", "on": "b.BrokerID = bc.BrokerID"}]}, "explanation": "- `MCBroker` 存储经纪商信息\n- `BCBrokerCash` 可能包含经纪商现金和佣金数据", "question_en": "How much commission has been paid to other brokers?", "rating": 6, "execution_result": null, "result_note": "当前查询需要验证经纪商佣金表关联", "tags": ["join", "ordering", "broker", "filter", "aggregation"], "difficulty": "hard"}
{"qid": "Q47", "question_zh": "今日/指定日期发放了多少份日结单或月结单?", "sql": "-- 查询报表发放统计 (2026-04-02)\nSELECT \n 'Daily Statement' AS StatementType,\n COUNT(*) AS StatementCount\nFROM MCAccount\nWHERE LastDailyStatementDate = '2026-04-02'\nUNION ALL\nSELECT \n 'Monthly Statement' AS StatementType,\n COUNT(*) AS StatementCount\nFROM MCAccount\nWHERE LastMonthlyStatementDate = '2026-04-02';", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 记录账户报表发送日期\n- `LastDailyStatementDate` 最近日结单发送日期", "question_en": "How many daily or monthly statements were issued today / on a specific date?", "rating": 9, "execution_result": null, "result_note": "", "tags": ["union", "filter", "aggregation"], "difficulty": "hard"}
{"qid": "Q48", "question_zh": "列出所有支持保证金的证券及其相应的保证金比例。", "sql": "-- 查询支持保证金的证券\nSELECT \n InstrumentID,\n Name AS InstrumentName,\n MarginPercentage AS MarginRatio,\n CASE \n WHEN MarginPercentage >= 0.7 THEN '高'\n WHEN MarginPercentage >= 0.5 THEN '中'\n WHEN MarginPercentage > 0 THEN '低'\n ELSE 'N/A'\n END AS RiskLevel,\n MarginLimitPerInstrument,\n CollateralRatio\nFROM MCInstrument\nWHERE MarginPercentage IS NOT NULL\n AND MarginPercentage > 0\n AND State = 'A'\nORDER BY MarginPercentage DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "MCInstrument", "columns": []}}, "joins": []}, "explanation": "- `MCInstrument` 存储证券信息\n- `MarginPercentage` 保证金比例", "question_en": "List all instruments that support margin and their corresponding margin ratios.", "rating": 9, "execution_result": null, "result_note": "| InstrumentID | InstrumentName | MarginRatio | RiskLevel |\n|-------------|----------------|-------------|-----------|\n| 00001 | CKH HOLDINGS(S) | 0.70 | 高 |\n| 00002 | CLP HOLDINGS(S) | 0.70 | 高 |\n| 00003 | HK & CHINA GAS(S) | 0.70 | 高 |\n\n(共767条记录)", "tags": ["margin", "limit", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q49", "question_zh": "本月、本季度和今年分别开了多少账户?", "sql": "-- 开户统计 (2026年4月)\nSELECT \n COUNT(CASE WHEN MONTH(OpenDate) = 4 AND YEAR(OpenDate) = 2026 THEN 1 END) AS April2026,\n COUNT(CASE WHEN DATEPART(QUARTER, OpenDate) = 2 AND YEAR(OpenDate) = 2026 THEN 1 END) AS Q2_2026,\n COUNT(CASE WHEN YEAR(OpenDate) = 2026 THEN 1 END) AS Year2026,\n COUNT(*) AS TotalAccounts,\n MIN(OpenDate) AS EarliestOpenDate,\n MAX(OpenDate) AS LatestOpenDate\nFROM MCAccount\nWHERE OpenDate IS NOT NULL;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.OpenDate` 账户开户日期\n- 按月、季度、年分别统计新开户数量", "question_en": "How many accounts were opened this month, this quarter, and this year?", "rating": 9, "execution_result": null, "result_note": "| April2026 | Q2_2026 | Year2026 | TotalAccounts | EarliestOpenDate | LatestOpenDate |\n|-----------|---------|----------|---------------|------------------|----------------|\n| 0 | 0 | 0 | 1,951 | 1993-03-05 | 2025-10-16 |", "tags": ["account", "limit", "filter", "aggregation"], "difficulty": "easy"}
{"qid": "Q50", "question_zh": "", "sql": "SELECT TOP\n\t15 c.ContractID,\n\tc.TradeDate,\n\tLTRIM( RTRIM( c.AccountID ) ) AS AccountID,\n\tLTRIM( RTRIM( c.MarketID ) ) AS MarketID,\n\tc.InstrumentID,\n\tc.BuySell,\n\tc.Quantity,\n\tc.Consideration,\n\tLTRIM( RTRIM( c.CurrencyID ) ) AS CurrencyID \nFROM\n\tdbo.TSBAccountContract c\n\tINNER JOIN dbo.MCAccount a ON c.AccountID = a.AccountID \nWHERE\n\tCAST ( c.TradeDate AS DATE ) = '2026-04-02' \n\tAND LTRIM( RTRIM( a.HouseAccountFlag ) ) = 'N' \nORDER BY\n\tc.ContractID;", "schema_info": {"tables": {"TSBAccountContract": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "", "question_en": "列出今天所有客戶的交易記錄", "rating": null, "execution_result": null, "result_note": "| ContractID | TradeDate | AccountID | MarketID | InstrumentID | BuySell | Quantity | Consideration | CurrencyID |\n| :--------- | :--------- | :-------- | :------- | :----------- | :------ | :------- | :------------ | :--------- |\n| B02403846 | 2026-04-02 | P011206 | HKEX | 01810 | B | 600 | 18360 | HKD |\n| B02403847 | 2026-04-02 | P011202 | HKEX | 01810 | B | 200 | 6120 | HKD |\n\n\n\n\n\n---\n\n## 附录:关键表说明\n\n| 表名 | 说明 | 关键字段 |\n|------|------|---------|\n| MCAccount | 账户主表 | AccountID, Name, MarketValue, MarginFacilityFlag |\n| MCUser | 用户表 | UserID, Name, Status, LogonEnableFlag |\n| BCAccountInstrument | 账户持仓 | AccountID, MarketID, Settled, DueBuy, DueSell |\n| BCAccountCash | 账户现金 | AccountID, TodayIn, TodayOut, AccruedInterest |\n| HCAccountMarginCallForDeposit | 追缴保证金 | AccountID, CallForDeposit, CallForDepositDate |\n| MCInstrument | 证券表 | InstrumentID, Name, MarginPercentage |\n| MCInstrumentIPODetail | IPO详情 | InstrumentID, Quantity, SubscriptionAmount |\n| MSBEntitlement | 权益分派 | EntitlementID, BalanceDate, BalanceExDate |\n| MCBroker | 经纪商 | BrokerID, Name |\n| MCLocation | 托管位置 | LocationID, Name, CCASSFlag |\n| HCExchangeRate | 汇率 | ExchangeRateID, ValueDate |\n| HCAccountCashRecord | 现金记录 | AccountID, ValueDate, LedgerBalance |\n\n---\n\n**文档结束**", "tags": ["join", "limit", "filter", "ordering"], "difficulty": "easy"}
+21
View File
@@ -0,0 +1,21 @@
{"qid": "Q2", "question_zh": "列出今日所有客户账户之间的股票转移记录。", "sql": "-- 查询今日客户账户间股票转移(参考日期:2026-04-02)\n-- 使用 TSBAccountInstrumentMovement,MovementType='T' 表示账户间转移\n-- ValueDate 为转移生效日期,关联 MCInstrument 获取证券名称\nSELECT \n m.MovementID,\n m.AccountID AS FromAccountID,\n m.TransferToAccountID,\n m.InstrumentID,\n i.Name AS InstrumentSymbol,\n m.MovementType,\n m.Quantity AS TransferQuantity,\n m.ValueDate AS TransferDate\nFROM TSBAccountInstrumentMovement m\nLEFT JOIN MCInstrument i ON m.InstrumentID = i.InstrumentID\nWHERE m.MovementType = 'T'\n AND m.ValueDate = '2026-04-02'\nORDER BY m.ValueDate;", "schema_info": {"tables": {"TSBAccountInstrumentMovement": {"alias": "m", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "LEFT", "on": "m.InstrumentID = i.InstrumentID"}]}, "explanation": "- `TSBAccountInstrumentMovement` 是持仓变动流水表,记录所有证券变动事件\n- `MovementType = 'T'`(Transfer)特指**账户间股票转移**,对应 `TransferToAccountID` 记录目标账户\n- `ValueDate` 是转移生效日期,可按日期过滤\n- 关联 `MCInstrument` 获取证券代码/名称\n- 注意:`BCAccountInstrument` 的 `TodayIn/TodayOut` 是**实时快照**,不带历史日期维度,不能用于查历史转移", "question_en": "List all stock transfers between client accounts performed today.", "rating": 9, "execution_result": null, "result_note": "当前查询无结果(测试环境中 `TSBAccountInstrumentMovement` 的 `MovementType='T'` 最新记录为 2025-10-21,无 2026-04-02 的账户间转移数据)", "tags": ["join", "ordering", "filter", "account", "left_join"], "difficulty": "hard"}
{"qid": "Q6", "question_zh": "所有货币的客户现金总余额是多少?", "sql": "-- 按货币统计客户现金余额\nSELECT \n CurrencyID,\n COUNT(DISTINCT AccountID) AS AccountCount,\n SUM(Settled) AS TotalSettledBalance,\n SUM(AccruedCreditInterest) AS TotalCreditInterest,\n SUM(AccruedDebitInterest) AS TotalDebitInterest,\n SUM(Settled) + SUM(AccruedCreditInterest) - SUM(AccruedDebitInterest) AS NetBalance\nFROM BCAccountCash\nGROUP BY CurrencyID\nORDER BY NetBalance DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `BCAccountCash` 记录账户现金余额\n- `Settled` 已结算余额\n- `AccruedCreditInterest` 应计存款利息\n- `AccruedDebitInterest` 应计借款利息", "question_en": "What is the total client cash balance across all currencies?", "rating": 9, "execution_result": null, "result_note": "| CurrencyID | AccountCount | TotalSettledBalance | NetBalance |\n|------------|-------------|--------------------|------------|\n| HKD | 2,906 | 52,195,305.77 | 52,195,305.77 |\n| TWD | 2 | -27,676.60 | -27,676.60 |\n| USD | 175 | 0 | 0 |\n| CNY | 95 | 0 | 0 |\n| GBP | 1 | 0 | 0 |", "tags": ["ordering", "account", "cash", "aggregation"], "difficulty": "medium"}
{"qid": "Q7", "question_zh": "今日结算后现金余额为负的账户列表。", "sql": "-- 查询现金余额为负的账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.Settled AS CashBalance,\n c.UnderdueCheque,\n c.BankAvailableBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.Settled < 0\nORDER BY c.Settled ASC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash.Settled` 表示已结算现金余额\n- 负数表示账户透支\n- 关联 `MCAccount` 获取账户名称", "question_en": "List accounts with negative cash balance after today's settlement.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | CurrencyID | CashBalance |\n|-----------|------------|------------|-------------|\n| M050009 | NG SUN SHU*** | HKD | -4,678,978.42 |\n| P050667 | WONG YIM HUNG | HKD | -780,196.94 |\n| M050521 | LO CHUN YIP | HKD | -290,487.54 |\n\n(共55个账户现金余额为负)", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q11", "question_zh": "哪些客户尚未缴纳IPO申购款?", "sql": "-- 查询未缴纳IPO申购款的账户\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.TotalBoughtQuantity AS SubscriptionLot,\n bi.TotalBoughtConsideration AS SubscriptionAmount\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nINNER JOIN MCInstrumentIPODetail ip ON bi.InstrumentID = ip.InstrumentID\nWHERE ip.State = 'A'\n AND bi.TotalBoughtConsideration > 0\n AND bi.TotalBoughtFee = 0\nORDER BY bi.TotalBoughtConsideration DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}, "MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}, {"type": "INNER", "on": "bi.InstrumentID = ip.InstrumentID"}]}, "explanation": "- 通过比对买卖数量和手续费判断是否缴款\n- `TotalBoughtConsideration > 0` 有认购\n- `TotalBoughtFee = 0` 未支付手续费", "question_en": "Which clients have not yet paid their IPO subscription money?", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "ordering"], "difficulty": "hard"}
{"qid": "Q14", "question_zh": "列出已申请但尚未处理的客户提款请求。", "sql": "-- 查询待处理提款申请 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.TodayOut AS WithdrawalAmount,\n c.BankAvailableBalance AS AvailableBalance,\n c.State AS RecordStatus\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.TodayOut > 0\nORDER BY c.TodayOut DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `TodayOut` 今日计划支出\n- 待处理提款申请应体现在此字段", "question_en": "Show all client withdrawals requested but not yet processed.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q16", "question_zh": "列出T+2交易缺少结算指令的账户。", "sql": "-- 查询T+2待交收但缺少指令的账户\n-- 注意:BCAccountInstrumentInstruction 表不存在,需改用 TSBSettlementInstruction\nSELECT \n bi.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.NextDayDueBuy AS T2DueBuy,\n bi.NextDayDueSell AS T2DueSell\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nWHERE (bi.NextDayDueBuy > 0 OR bi.NextDayDueSell > 0)\n AND NOT EXISTS (\n SELECT 1 FROM TSBSettlementInstruction si\n WHERE si.AccountOrBrokerID = bi.AccountID\n AND si.InstrumentID = bi.InstrumentID\n AND si.State IN ('P','A')\n );", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}, "TSBSettlementInstruction": {"alias": "si", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}]}, "explanation": "- `NextDayDueBuy/NextDayDueSell` T+2交收数量(次日到期)\n- `TSBSettlementInstruction` 是结算指令表,通过 `NOT EXISTS` 排除已有指令的记录\n- `BCAccountInstrumentInstruction` 表不存在,不能使用", "question_en": "Show accounts where settlement instruction is missing for T+2 trades.", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "trade"], "difficulty": "medium"}
{"qid": "Q17", "question_zh": "哪些客户已超过其信用额度?", "sql": "-- 查询超信用额度客户(使用 MarginLimit)\n-- 注意:MCAccount 无 CreditLimit 字段,应用 MarginLimit\nSELECT \n AccountID,\n Name AS AccountName,\n MarginLimit,\n MarketValue,\n MarginLimit - MarketValue AS AvailableCredit,\n CASE \n WHEN MarketValue > MarginLimit THEN '超额'\n WHEN MarketValue > MarginLimit * 0.8 THEN '接近限额'\n ELSE '正常'\n END AS Status\nFROM MCAccount\nWHERE MarginLimit > 0\n AND MarketValue > MarginLimit * 0.8\nORDER BY (MarketValue - MarginLimit) DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.MarginLimit` 保证金/信用限额(注意:无 `CreditLimit` 字段)\n- `MCAccount.MarketValue` 持仓市值\n- `MarginBLimit` 是单独借款限额,注意区分", "question_en": "Which clients have exceeded their credit limit?", "rating": 7, "execution_result": null, "result_note": "当前查询无超限客户", "tags": ["account", "limit", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q21", "question_zh": "截至昨日的客户借方余额应计利息是多少?", "sql": "-- 查询客户借方余额应计利息 (截至2026-04-01)\nSELECT \n SUM(AccruedDebitInterest) AS TotalDebitInterestAccrued,\n SUM(AccruedCreditInterest) AS TotalCreditInterestAccrued,\n SUM(AccruedDebitInterest) - SUM(AccruedCreditInterest) AS NetDebitInterest,\n COUNT(DISTINCT AccountID) AS AccountCount\nFROM BCAccountCash\nWHERE AccruedDebitInterest > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `AccruedDebitInterest` 借款应计利息\n- `AccruedCreditInterest` 存款应计利息", "question_en": "What is the interest accrued on client debit balances as of yesterday?", "rating": 8, "execution_result": null, "result_note": "| TotalDebitInterestAccrued | TotalCreditInterestAccrued | NetDebitInterest | AccountCount |\n|---------------------------|---------------------------|-----------------|-------------|\n| 2,022.70 | 464.15 | 1,558.55 | 55 |", "tags": ["filter", "account", "interest", "cash", "aggregation"], "difficulty": "hard"}
{"qid": "Q22", "question_zh": "列出今日所有公司账户与客户账户之间的现金划转。", "sql": "-- 查询公司账户与客户账户现金划转 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n a.AccountType,\n c.CurrencyID,\n c.TodayIn AS CashInflow,\n c.TodayOut AS CashOutflow,\n c.Settled AS CurrentBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE (c.TodayIn > 0 OR c.TodayOut > 0)\nORDER BY c.TodayIn + c.TodayOut DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- 公司账户与客户账户通过 `AccountType` 区分\n- `TodayIn/TodayOut` 记录现金流动", "question_en": "List all cash movements between house and client accounts today.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q23", "question_zh": "列出所有逾期未付保证金利息的账户。", "sql": "-- 查询逾期保证金利息账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.LoanInterestMarginOverdue AS MarginOverdueInterest,\n c.LoanInterestMarginBOverdue AS MarginBOverdueInterest,\n c.LoanInterestOverdue AS GeneralOverdueInterest\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.LoanInterestMarginOverdue > 0 \n OR c.LoanInterestMarginBOverdue > 0\n OR c.LoanInterestOverdue > 0\nORDER BY (c.LoanInterestMarginOverdue + c.LoanInterestMarginBOverdue + c.LoanInterestOverdue) DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `LoanInterestMarginOverdue` 保证金账户逾期利息\n- `LoanInterestMarginBOverdue` B类保证金逾期利息", "question_en": "Show all accounts with overdue margin interest payments.", "rating": 8, "execution_result": null, "result_note": "当前查询无逾期利息记录", "tags": ["join", "ordering", "margin", "filter", "account", "interest"], "difficulty": "hard"}
{"qid": "Q24", "question_zh": "有多少客户报表已生成成功但尚未发送?", "sql": "-- 查询已生成但未发送的报表\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n a.LastDailyStatementDate,\n a.LastMonthlyStatementDate,\n a.LastStatementGenerateTime,\n a.LastStatementSendTime,\n CASE \n WHEN a.LastStatementGenerateTime > a.LastStatementSendTime THEN '未发送'\n ELSE '已发送'\n END AS DeliveryStatus\nFROM MCAccount a\nWHERE a.LastStatementGenerateTime IS NOT NULL\n AND (a.LastStatementSendTime IS NULL \n OR a.LastStatementGenerateTime > a.LastStatementSendTime)\nORDER BY a.LastStatementGenerateTime DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `LastStatementGenerateTime` 报表生成时间\n- `LastStatementSendTime` 报表发送时间", "question_en": "How many client statements were successfully generated but not yet delivered?", "rating": 7, "execution_result": null, "result_note": "当前查询无未发送报表", "tags": ["ordering", "account", "filter", "statement"], "difficulty": "easy"}
{"qid": "Q27", "question_zh": "列出所有超过3天的暂记账户分录。", "sql": "-- 查询超过3天的暂记账户分录 (2026-04-02)\n-- 说明:TCAccountCashMovement 是现金流水表\n-- NeedHoldFlag='Y' 表示暂记分录\n-- Amount - ReleasedAmount 表示未释放金额(暂记余额)\n-- 筛选未释放且超过3天的暂记分录\nSELECT \n cm.AccountID,\n cm.MovementID,\n cm.ValueDate,\n cm.CurrencyID,\n cm.Amount - ISNULL(cm.ReleasedAmount, 0) AS PendingBalance,\n cm.Remark,\n DATEDIFF(DAY, cm.ValueDate, '2026-04-02') AS DaysOutstanding\nFROM TCAccountCashMovement cm\nWHERE cm.NeedHoldFlag = 'Y'\n AND cm.Amount - ISNULL(cm.ReleasedAmount, 0) != 0\n AND DATEDIFF(DAY, cm.ValueDate, '2026-04-02') > 3\nORDER BY DaysOutstanding DESC, PendingBalance DESC;", "schema_info": {"tables": {"TCAccountCashMovement": {"alias": "cm", "columns": []}}, "joins": []}, "explanation": "- `TCAccountCashMovement` 存储现金流水记录\n- `NeedHoldFlag = 'Y'` 标识暂记(待确认)分录\n- `Amount - ReleasedAmount` 计算未释放的暂记余额\n- `DATEDIFF` 计算距今天数\n- `DATEDIFF > 3` 筛选超过3天的记录", "question_en": "List all suspense account entries older than 3 days.", "rating": 9, "execution_result": null, "result_note": "**查询结果:0条记录**\n\n当前没有超过3天未释放的暂记账户分录。所有暂记分录的 ReleasedAmount = Amount,已全部释放。", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q28", "question_zh": "哪些客户已请求更改结算货币?", "sql": "-- 查询请求更改结算货币的客户\n-- 说明:经查 MCAccountCurrency 表无 CurrencyChangeStatus/RequestedCurrencyID 等字段\n-- 数据库中没有专门的货币变更请求表\n-- 此查询基于账户货币历史时间表(HCAccountCurrencyTimetable)展示货币生效安排\nSELECT \n act.AccountID,\n mca.Name AS AccountName,\n act.CurrencyID AS Currency,\n act.EffectiveDateFrom,\n act.EffectiveDateTo,\n act.AccountTypeID\nFROM HCAccountCurrencyTimetable act\nINNER JOIN MCAccount mca ON act.AccountID = mca.AccountID\nWHERE act.EffectiveDateTo IS NULL\nORDER BY act.EffectiveDateFrom DESC;", "schema_info": {"tables": {"HCAccountCurrencyTimetable": {"alias": "act", "columns": []}, "MCAccount": {"alias": "mca", "columns": []}}, "joins": [{"type": "INNER", "on": "act.AccountID = mca.AccountID"}]}, "explanation": "- `HCAccountCurrencyTimetable` 记录账户货币生效时间表\n- `EffectiveDateTo IS NULL` 表示当前生效的货币配置\n- 如需货币变更请求功能,建议在系统中扩展相关表结构", "question_en": "Which clients have requested a change in settlement currency?", "rating": 4, "execution_result": null, "result_note": "**说明:** 数据库中没有专门的货币变更请求表。`MCAccountCurrency` 表仅记录账户当前货币配置,无变更请求字段。", "tags": ["join", "account", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q29", "question_zh": "列出后台系统中所有活跃用户账户及其最后登录日期。", "sql": "-- 查询活跃用户及其登录情况\nSELECT \n u.UserID,\n u.Name AS UserName,\n u.Status,\n u.LogonEnableFlag,\n u.LastLogonTime,\n u.BranchID,\n CASE u.CompanyAEFlag WHEN 'Y' THEN '公司经纪' ELSE '个人' END AS AEType,\n CASE \n WHEN u.LastLogonTime >= DATEADD(DAY, -7, GETDATE()) THEN '近7天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -30, GETDATE()) THEN '近30天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -90, GETDATE()) THEN '近90天活跃'\n ELSE '长期未登录'\n END AS ActivityStatus\nFROM MCUser u\nWHERE u.State = 'A'\n AND u.LogonEnableFlag = 'Y'\nORDER BY u.LastLogonTime DESC;", "schema_info": {"tables": {"MCUser": {"alias": "u", "columns": []}}, "joins": []}, "explanation": "- `MCUser` 存储用户信息\n- `LastLogonTime` 最后登录时间", "question_en": "List all active user accounts in the back office system with last login date.", "rating": 9, "execution_result": null, "result_note": "| UserID | UserName | Status | LogonEnableFlag | LastLogonTime | ActivityStatus |\n|--------|----------|--------|-----------------|---------------|----------------|\n| SUPPORT | SUPPORT | N | Y | 2026-04-08 | 近7天活跃 |\n| ROSANNA | ROSANNA | N | Y | 2025-10-21 | 长期未登录 |\n| SING | WONG LO SING | N | Y | 2025-10-21 | 长期未登录 |\n| LEONNG | LEON NG | N | Y | 2025-10-21 | 长期未登录 |", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q32", "question_zh": "各市场客户不同资产(如股票、债券、基金、虚拟资产)的总持仓是多少?", "sql": "-- 按市场统计客户持仓\nSELECT \n b.MarketID,\n COUNT(DISTINCT b.AccountID) AS AccountCount,\n SUM(b.Settled) AS TotalQuantity,\n SUM(b.CostAmount) AS TotalCostAmount,\n SUM(b.TotalBoughtQuantity) AS TotalBoughtQty,\n SUM(b.TotalSoldQuantity) AS TotalSoldQty\nFROM BCAccountInstrument b\nGROUP BY b.MarketID\nORDER BY TotalCostAmount DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "b", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表记录账户在各市场的持仓\n- `MarketID` 区分不同市场", "question_en": "What is the total client holding of different assets (e.g., stocks, bonds, funds, virtual assets) by each market?", "rating": 8, "execution_result": null, "result_note": "| MarketID | AccountCount | TotalQuantity | TotalCostAmount | TotalBoughtQty | TotalSoldQty |\n|----------|-------------|---------------|-----------------|---------------|-------------|\n| HKEX | 2,102 | 717,471,548 | 87,813,213.45 | 1,015,923,906 | 298,452,798 |\n| SETW | 2 | 3,100 | 32,298.50 | 4,100 | 1,000 |", "tags": ["account", "holding", "ordering", "aggregation"], "difficulty": "medium"}
{"qid": "Q34", "question_zh": "保证金账户前20大持仓(按市值)是多少?", "sql": "-- 保证金账户按市值排序的前20持仓\nSELECT TOP 20\n a.AccountID,\n a.Name AS AccountName,\n a.MarketValue,\n a.MarginDebitRatio AS MarginDebitBalanceRatio,\n a.MarginPosition,\n a.CallForDeposit,\n a.MarginFacilityFlag\nFROM MCAccount a\nWHERE a.MarginFacilityFlag = 'Y'\n AND a.State = 'A'\n AND a.MarketValue > 0\nORDER BY a.MarketValue DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 表包含所有账户信息\n- `MarginFacilityFlag = 'Y'` 筛选保证金账户", "question_en": "What are the top 20 holdings (based on market value) for margin accounts?", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginPosition |\n|-----------|-------------|------------|----------------|\n| M050009 | NG SUN SHU*** | 57,420,000 | 35,515,021.58 |\n| M050013 | NG CHUNG WAI*** | 19,504,520 | 10,918,958.78 |\n| M050193 | WONG KING YIU*** ^ | 11,682,920 | 3,340,099.05 |\n| P020160 | LAW SHIU MING DENNIS | 7,520,370 | 0 |\n| P030078 | MAK SUI BING | 7,120,309.94 | 0 |\n| P051101 | CHUNG CHUNG YEE | 7,117,808.04 | 0 |\n| M050170 | FUNG LAI FONG ANNA | 7,009,227.25 | 4,136,857 |\n| P220005 | LAI KAM SUI # | 5,837,102.10 | 97.97 |\n| P280628 | CHAN KWOK MO # | 5,761,997.48 | 62,508.23 |\n| P280455 | LEUNG KA CHI # | 5,487,971.20 | -64,981.22 |\n\n(共20条记录,以上展示前10条)", "tags": ["ordering", "holding", "margin", "filter", "limit", "account"], "difficulty": "hard"}
{"qid": "Q35", "question_zh": "列出本月按客户主任分组的佣金总额,以及相应的成交金额和返佣金额。", "sql": "-- 按经纪商/客户主任分组的佣金统计\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee) AS TotalBuyCommission,\n SUM(bi.TotalSoldFee) AS TotalSellCommission,\n SUM(bi.TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(bi.TotalSoldConsideration) AS TotalSellConsideration,\n SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE a.State = 'A'\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCAccount.AEID` 关联经纪商/客户主任\n- `BCAccountInstrument` 包含交易费用数据", "question_en": "List the total commission received this month by AE, along with corresponding consideration and rebate amounts.", "rating": 8, "execution_result": null, "result_note": "| AEID | AEName | AccountCount | TotalBuyCommission | TotalSellCommission | TotalCommission |\n|------|--------|-------------|-------------------|--------------------|----------------|\n| C01 | CHAN YUET HUNG | 628 | 183,244.64 | 187,220.59 | 370,465.23 |\n| C28 | CHAN SHU SHAN | 405 | 179,275.89 | 176,760.39 | 356,036.28 |\n| C05 | CENTRAL | 517 | 97,368.51 | 102,819.88 | 200,188.39 |\n| C33 | LEON NG | 13 | 71,541.06 | 72,620.60 | 144,161.66 |\n| C07 | CHAN WING PAI | 75 | 73,255.68 | 69,115.58 | 142,371.26 |\n| C10 | TOKWAWAN / KOWLOON CITY | 369 | 51,059.78 | 57,288.86 | 108,348.64 |\n| C08 | WONG HON KONG | 380 | 47,505.15 | 46,300.39 | 93,805.54 |\n| C36 | Name Of C36 | 146 | 40,945.66 | 35,682.86 | 76,628.52 |\n| C66 | CHEUNG YUK LING IVA | 17 | 24,458.82 | 22,723.18 | 47,182.00 |\n| C19 | WONG LO SING | 60 | 13,337.69 | 13,912.30 | 27,249.99 |\n\n(共15个AE有佣金记录,以上展示前10条)\n\n**注:** 当前SQL无日期条件,统计所有历史累计佣金。如需\"本月\"佣金,需添加 `LastTransactionDate >= '2026-04-01'` 条件。", "tags": ["join", "ordering", "filter", "account", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q43", "question_zh": "列出持仓为负数(透支)的账户。", "sql": "-- 查询透支持仓账户\nSELECT \n AccountID,\n Name AS AccountName,\n MarketValue,\n AssetBalance,\n LiabilityBalance,\n MarginPosition,\n MarginFacilityFlag\nFROM MCAccount\nWHERE MarketValue < 0\n AND State = 'A'\nORDER BY MarketValue ASC;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MarketValue < 0` 筛选持仓为负的账户\n- 持仓为负通常表示账户存在透支或结算问题", "question_en": "List accounts with overdrawn positions.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginFacilityFlag |\n|-----------|-------------|-------------|-------------------|\n| P030012 | LAI YEE TAK HELEN | -112,196.60 | N |\n| P350022 | CHAN YAU KING*** | -92,950.00 | N |\n| P011212 | NG SIU PING | -12,352.00 | N |", "tags": ["account", "holding", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q44", "question_zh": "本月收到/支付的利息金额是多少(如客户借款利息和存款利息)?", "sql": "-- 本月利息收支汇总 (2026年4月)\nSELECT \n SUM(AccruedCreditInterest) AS CreditInterest,\n SUM(AccruedDebitInterest) AS DebitInterest,\n SUM(AccruedCreditInterest) - SUM(AccruedDebitInterest) AS NetInterest\nFROM BCAccountCash;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `BCAccountCash` 记录账户现金和利息信息\n- `AccruedCreditInterest` 应计存款利息", "question_en": "What is the interest amount received/paid this month (e.g., client debit interest and credit interest)?", "rating": 7, "execution_result": null, "result_note": "| CreditInterest | DebitInterest | NetInterest |\n|----------------|---------------|-------------|\n| 464.15 | 2,022.70 | -1,558.55 |", "tags": ["account", "aggregation", "interest"], "difficulty": "easy"}
{"qid": "Q45", "question_zh": "不同经纪商(如非中央结算系统持仓)的客户总持仓是多少?", "sql": "-- 按托管位置统计持仓(非CCASS)\nSELECT \n loc.LocationID,\n loc.Name AS LocationName,\n COUNT(DISTINCT bi.AccountID) AS AccountCount,\n SUM(bi.Settled) AS TotalQuantity,\n SUM(bi.CostAmount) AS TotalCostAmount\nFROM BCAccountLocationInstrument bi\nINNER JOIN MCLocation loc ON bi.LocationID = loc.LocationID\nWHERE loc.CCASSFlag = 'N'\nGROUP BY loc.LocationID, loc.Name\nORDER BY TotalQuantity DESC;", "schema_info": {"tables": {"BCAccountLocationInstrument": {"alias": "bi", "columns": []}, "MCLocation": {"alias": "loc", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.LocationID = loc.LocationID"}]}, "explanation": "- `BCAccountLocationInstrument` 记录按托管位置分类的持仓\n- `MCLocation` 存储托管位置信息", "question_en": "What is the total client holding at different broker firms (e.g., non-CCASS locations)?", "rating": 7, "execution_result": null, "result_note": "当前查询需要验证 Location 表关联", "tags": ["join", "ordering", "holding", "broker", "filter", "account", "aggregation"], "difficulty": "hard"}
{"qid": "Q49", "question_zh": "本月、本季度和今年分别开了多少账户?", "sql": "-- 开户统计 (2026年4月)\nSELECT \n COUNT(CASE WHEN MONTH(OpenDate) = 4 AND YEAR(OpenDate) = 2026 THEN 1 END) AS April2026,\n COUNT(CASE WHEN DATEPART(QUARTER, OpenDate) = 2 AND YEAR(OpenDate) = 2026 THEN 1 END) AS Q2_2026,\n COUNT(CASE WHEN YEAR(OpenDate) = 2026 THEN 1 END) AS Year2026,\n COUNT(*) AS TotalAccounts,\n MIN(OpenDate) AS EarliestOpenDate,\n MAX(OpenDate) AS LatestOpenDate\nFROM MCAccount\nWHERE OpenDate IS NOT NULL;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.OpenDate` 账户开户日期\n- 按月、季度、年分别统计新开户数量", "question_en": "How many accounts were opened this month, this quarter, and this year?", "rating": 9, "execution_result": null, "result_note": "| April2026 | Q2_2026 | Year2026 | TotalAccounts | EarliestOpenDate | LatestOpenDate |\n|-----------|---------|----------|---------------|------------------|----------------|\n| 0 | 0 | 0 | 1,951 | 1993-03-05 | 2025-10-16 |", "tags": ["account", "limit", "filter", "aggregation"], "difficulty": "easy"}
+17
View File
@@ -0,0 +1,17 @@
{"qid": "Q1", "question_zh": "按对手方列出截至[日期]的所有未结算交易。", "sql": "-- 按对手方统计截至 2026-04-02 的未结算交易\n-- 使用 TSBBrokerContract(经纪商合约表),按 BrokerID(对手方经纪商)分组\n-- SettleStatus='U' 表示未结算;CashSettleDate <= '2026-04-02' 筛选截至日\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n COUNT(*) AS UnsettledTradeCount,\n SUM(b.SettleQuantity) AS TotalUnsettledQty,\n SUM(b.SettleAmount) AS TotalUnsettledAmount,\n MIN(b.BuySell) + '~' + MAX(b.BuySell) AS BuySellRange,\n MIN(b.CashSettleDate) AS EarliestSettleDate,\n MAX(b.CashSettleDate) AS LatestSettleDate\nFROM TSBBrokerContract b\nLEFT JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.SettleStatus = 'U'\n AND b.CashSettleDate <= '2026-04-02'\nGROUP BY b.BrokerID, m.Name\nORDER BY TotalUnsettledAmount DESC;", "schema_info": {"tables": {"TSBBrokerContract": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "LEFT", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `TSBBrokerContract` 是经纪商/对手方合约表,记录与外部对手方的交易合约,`BrokerID` 即对手方标识\n- `SettleStatus = 'U'` 表示未结算;`CashSettleDate <= '2026-04-02'` 筛选截至日未结清的合约\n- 关联 `MCBroker` 获取对手方经纪商名称\n- 按 `BrokerID` 分组汇总未结算数量和金额", "question_en": "Show all unsettled trades as of [date] grouped by counterparty.", "rating": 9, "execution_result": null, "result_note": "| BrokerID | BrokerName | UnsettledTradeCount | TotalUnsettledQty | TotalUnsettledAmount | BuySellRange | EarliestSettleDate | LatestSettleDate |\n|----------|-----------|---------------------|-------------------|---------------------|--------------|---------------------|-------------------|\n| CCASS | CCASS | 622 | 40,459,253 | 44,173,571.06 | B~S | 2025-07-30 | 2026-04-02 |\n\n> **注**:CCASS(Hong Kong Securities Clearing Company Limited)是香港交易所的中央结算机构,作为交易所交易的核心对手方。622笔未结算合约均为 HKEX 市场。", "tags": ["join", "ordering", "broker", "filter", "trade", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q6", "question_zh": "所有货币的客户现金总余额是多少?", "sql": "-- 按货币统计客户现金余额\nSELECT \n CurrencyID,\n COUNT(DISTINCT AccountID) AS AccountCount,\n SUM(Settled) AS TotalSettledBalance,\n SUM(AccruedCreditInterest) AS TotalCreditInterest,\n SUM(AccruedDebitInterest) AS TotalDebitInterest,\n SUM(Settled) + SUM(AccruedCreditInterest) - SUM(AccruedDebitInterest) AS NetBalance\nFROM BCAccountCash\nGROUP BY CurrencyID\nORDER BY NetBalance DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `BCAccountCash` 记录账户现金余额\n- `Settled` 已结算余额\n- `AccruedCreditInterest` 应计存款利息\n- `AccruedDebitInterest` 应计借款利息", "question_en": "What is the total client cash balance across all currencies?", "rating": 9, "execution_result": null, "result_note": "| CurrencyID | AccountCount | TotalSettledBalance | NetBalance |\n|------------|-------------|--------------------|------------|\n| HKD | 2,906 | 52,195,305.77 | 52,195,305.77 |\n| TWD | 2 | -27,676.60 | -27,676.60 |\n| USD | 175 | 0 | 0 |\n| CNY | 95 | 0 | 0 |\n| GBP | 1 | 0 | 0 |", "tags": ["ordering", "account", "cash", "aggregation"], "difficulty": "medium"}
{"qid": "Q12", "question_zh": "本月累计的结算失败罚金是多少?", "sql": "-- 查询本月结算失败罚金 (2026年4月)\n-- 注意:BCAccountInstrument 无 FailedTradePenalty 字段,需另找结算罚金存储位置\n-- 目前未找到结算失败罚金字段,建议通过 TSBBrokerContract 或 BCBrokerCash 进一步排查\nSELECT \n COUNT(*) AS FailedTradeCount,\n MarketID\nFROM BCAccountInstrument\nWHERE YEAR(LastTransactionDate) = 2026\n AND MONTH(LastTransactionDate) = 4\nGROUP BY MarketID;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 无 `FailedTradePenalty` 字段,原始 SQL 会报错\n- `TSBBrokerContract` 或 `BCBrokerCash` 中可能存储结算相关费用,需进一步确认", "question_en": "What is the total failed trade penalty incurred this month?", "rating": 3, "execution_result": null, "result_note": "当前查询无结果(BCAccountInstrument 表无 FailedTradePenalty 字段,无法统计结算罚金)", "tags": ["filter", "aggregation"], "difficulty": "medium"}
{"qid": "Q15", "question_zh": "本月应付给介绍经纪人的佣金返佣总额是多少?", "sql": "-- 查询本月应付返佣 (2026年4月)\n-- 注意:BCAccountInstrument 无 UpdatedAt 字段,用 LastTransactionDate 过滤本月有交易的账户\n-- 说明:TotalBoughtFee/TotalSoldFee 为历史累计字段,此处统计近期活跃账户的累计佣金供参考\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE YEAR(bi.LastTransactionDate) = 2026\n AND MONTH(bi.LastTransactionDate) = 4\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee + bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCRebateScheme` 可能存储返佣规则\n- 按AE汇总佣金", "question_en": "What is the total commission rebate payable to introducing brokers this month?", "rating": 6, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q21", "question_zh": "截至昨日的客户借方余额应计利息是多少?", "sql": "-- 查询客户借方余额应计利息 (截至2026-04-01)\nSELECT \n SUM(AccruedDebitInterest) AS TotalDebitInterestAccrued,\n SUM(AccruedCreditInterest) AS TotalCreditInterestAccrued,\n SUM(AccruedDebitInterest) - SUM(AccruedCreditInterest) AS NetDebitInterest,\n COUNT(DISTINCT AccountID) AS AccountCount\nFROM BCAccountCash\nWHERE AccruedDebitInterest > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `AccruedDebitInterest` 借款应计利息\n- `AccruedCreditInterest` 存款应计利息", "question_en": "What is the interest accrued on client debit balances as of yesterday?", "rating": 8, "execution_result": null, "result_note": "| TotalDebitInterestAccrued | TotalCreditInterestAccrued | NetDebitInterest | AccountCount |\n|---------------------------|---------------------------|-----------------|-------------|\n| 2,022.70 | 464.15 | 1,558.55 | 55 |", "tags": ["filter", "account", "interest", "cash", "aggregation"], "difficulty": "hard"}
{"qid": "Q26", "question_zh": "本月各交易所的结算费用明细如何?", "sql": "-- 按交易所统计结算费用 (2026年4月)\n-- 说明:BCAccountInstrument 表中 TotalBoughtFee/TotalSoldFee 是持仓级别的交易费用字段\n-- LastTransactionDate 表示该持仓最后交易日期\n-- 查询逻辑:筛选最后交易日期在本月内的持仓记录,按交易所汇总交易费用\nSELECT \n bi.MarketID,\n m.MarketName,\n SUM(bi.TotalBoughtFee) AS TotalBuyFee,\n SUM(bi.TotalSoldFee) AS TotalSellFee,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalSettlementFee,\n COUNT(DISTINCT bi.AccountID) AS TradingAccountCount\nFROM BCAccountInstrument bi\nINNER JOIN MCMarket m ON bi.MarketID = m.MarketID\nWHERE bi.LastTransactionDate >= '2026-04-01' AND bi.LastTransactionDate < '2026-05-01'\nGROUP BY bi.MarketID, m.MarketName\nORDER BY TotalSettlementFee DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCMarket": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.MarketID = m.MarketID"}]}, "explanation": "- `BCAccountInstrument` 存储持仓级别信息,包含各持仓的交易费用累计\n- `MCMarket` 存储市场信息,提供市场名称\n- `LastTransactionDate` 用于过滤本月有交易的持仓记录\n- 按市场分组汇总结算费用", "question_en": "What is the breakdown of settlement fees by exchange for this month?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "trade", "aggregation", "date_range"], "difficulty": "hard"}
{"qid": "Q30", "question_zh": "按结算日期划分的未结算交易总风险敞口是多少?", "sql": "-- 按结算日期分组的未结算交易敞口\nSELECT \n SettlementType,\n SUM(Amount) AS TotalExposure\nFROM (\n SELECT 'DueBuy_T1' AS SettlementType, SUM(DueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'DueSell_T1' AS SettlementType, SUM(DueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueBuy' AS SettlementType, SUM(NextDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueSell' AS SettlementType, SUM(NextDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueBuy' AS SettlementType, SUM(NextTwoDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueSell' AS SettlementType, SUM(NextTwoDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueBuy' AS SettlementType, SUM(TodayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueSell' AS SettlementType, SUM(TodayDueSell) AS Amount FROM BCAccountInstrument\n) t\nGROUP BY SettlementType\nORDER BY SettlementType;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表包含所有账户的证券持仓和交收信息\n- `DueBuy/DueSell` 表示T+1到期的买卖数量", "question_en": "What is the total exposure from unsettled trades by settlement date?", "rating": 8, "execution_result": null, "result_note": "| SettlementType | TotalExposure |\n|----------------|---------------|\n| DueBuy_T1 | 0 |\n| DueSell_T1 | 0 |\n| NextDayDueBuy | 0 |\n| NextDayDueSell | 0 |\n| NextTwoDayDueBuy | 0 |\n| NextTwoDayDueSell | 0 |\n| TodayDueBuy | 1,800 |\n| TodayDueSell | 1,000 |\n\n**注:** `DueBuy/DueSell` 等字段表示应交收数量(T+1/T+2/今日),非金额敞口。如需金额敞口,需乘以价格。", "tags": ["union", "trade", "ordering", "aggregation"], "difficulty": "hard"}
{"qid": "Q31", "question_zh": "指定日期或日期范围内收到的交易量(如成交金额)及相应佣金是多少?", "sql": "-- 交易量和佣金统计\nSELECT \n SUM(TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(TotalBoughtFee) AS TotalBuyCommission,\n SUM(TotalSoldConsideration) AS TotalSellConsideration,\n SUM(TotalSoldFee) AS TotalSellCommission,\n SUM(TotalBoughtConsideration) + SUM(TotalSoldConsideration) AS TotalConsideration,\n SUM(TotalBoughtFee) + SUM(TotalSoldFee) AS TotalCommission\nFROM BCAccountInstrument;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表记录了账户所有历史买卖交易\n- `TotalBoughtConsideration / TotalSoldConsideration`: 买卖成交金额", "question_en": "What is the trading volume (e.g., consideration) and corresponding commission amount received for a specific date or date range?", "rating": 9, "execution_result": null, "result_note": "| TotalBuyConsideration | TotalBuyCommission | TotalSellConsideration | TotalSellCommission | TotalConsideration | TotalCommission |\n|---------------------|-------------------|----------------------|--------------------|-------------------|-----------------|\n| 945,480,833.78 | 793,149.07 | 278,693,891.64 | 809,248.89 | 1,224,174,725.42 | 1,602,397.96 |", "tags": ["trade", "aggregation"], "difficulty": "easy"}
{"qid": "Q32", "question_zh": "各市场客户不同资产(如股票、债券、基金、虚拟资产)的总持仓是多少?", "sql": "-- 按市场统计客户持仓\nSELECT \n b.MarketID,\n COUNT(DISTINCT b.AccountID) AS AccountCount,\n SUM(b.Settled) AS TotalQuantity,\n SUM(b.CostAmount) AS TotalCostAmount,\n SUM(b.TotalBoughtQuantity) AS TotalBoughtQty,\n SUM(b.TotalSoldQuantity) AS TotalSoldQty\nFROM BCAccountInstrument b\nGROUP BY b.MarketID\nORDER BY TotalCostAmount DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "b", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表记录账户在各市场的持仓\n- `MarketID` 区分不同市场", "question_en": "What is the total client holding of different assets (e.g., stocks, bonds, funds, virtual assets) by each market?", "rating": 8, "execution_result": null, "result_note": "| MarketID | AccountCount | TotalQuantity | TotalCostAmount | TotalBoughtQty | TotalSoldQty |\n|----------|-------------|---------------|-----------------|---------------|-------------|\n| HKEX | 2,102 | 717,471,548 | 87,813,213.45 | 1,015,923,906 | 298,452,798 |\n| SETW | 2 | 3,100 | 32,298.50 | 4,100 | 1,000 |", "tags": ["account", "holding", "ordering", "aggregation"], "difficulty": "medium"}
{"qid": "Q35", "question_zh": "列出本月按客户主任分组的佣金总额,以及相应的成交金额和返佣金额。", "sql": "-- 按经纪商/客户主任分组的佣金统计\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee) AS TotalBuyCommission,\n SUM(bi.TotalSoldFee) AS TotalSellCommission,\n SUM(bi.TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(bi.TotalSoldConsideration) AS TotalSellConsideration,\n SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE a.State = 'A'\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCAccount.AEID` 关联经纪商/客户主任\n- `BCAccountInstrument` 包含交易费用数据", "question_en": "List the total commission received this month by AE, along with corresponding consideration and rebate amounts.", "rating": 8, "execution_result": null, "result_note": "| AEID | AEName | AccountCount | TotalBuyCommission | TotalSellCommission | TotalCommission |\n|------|--------|-------------|-------------------|--------------------|----------------|\n| C01 | CHAN YUET HUNG | 628 | 183,244.64 | 187,220.59 | 370,465.23 |\n| C28 | CHAN SHU SHAN | 405 | 179,275.89 | 176,760.39 | 356,036.28 |\n| C05 | CENTRAL | 517 | 97,368.51 | 102,819.88 | 200,188.39 |\n| C33 | LEON NG | 13 | 71,541.06 | 72,620.60 | 144,161.66 |\n| C07 | CHAN WING PAI | 75 | 73,255.68 | 69,115.58 | 142,371.26 |\n| C10 | TOKWAWAN / KOWLOON CITY | 369 | 51,059.78 | 57,288.86 | 108,348.64 |\n| C08 | WONG HON KONG | 380 | 47,505.15 | 46,300.39 | 93,805.54 |\n| C36 | Name Of C36 | 146 | 40,945.66 | 35,682.86 | 76,628.52 |\n| C66 | CHEUNG YUK LING IVA | 17 | 24,458.82 | 22,723.18 | 47,182.00 |\n| C19 | WONG LO SING | 60 | 13,337.69 | 13,912.30 | 27,249.99 |\n\n(共15个AE有佣金记录,以上展示前10条)\n\n**注:** 当前SQL无日期条件,统计所有历史累计佣金。如需\"本月\"佣金,需添加 `LastTransactionDate >= '2026-04-01'` 条件。", "tags": ["join", "ordering", "filter", "account", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q36", "question_zh": "各市场(如港股T+1和T+2、美股T+1)的待结算金额是多少?", "sql": "-- 按市场统计待结算金额\nSELECT \n MarketID,\n SUM(DueBuy + DueSell) AS TotalPendingQty,\n SUM(NextDayDueBuy + NextDayDueSell) AS T2TotalPendingQty\nFROM BCAccountInstrument\nWHERE DueBuy > 0 OR DueSell > 0 OR NextDayDueBuy > 0 OR NextDayDueSell > 0\nGROUP BY MarketID;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 记录各市场的待交收数量\n- `DueBuy/DueSell` 对应T+1交收", "question_en": "What is the pending settlement amount for each market (e.g., HK T+1 & T+2, US T+1)?", "rating": 7, "execution_result": null, "result_note": "| MarketID | TotalPendingQty | T2TotalPendingQty |\n|----------|----------------|------------------|\n| HKEX | 0 | 0 |\n| SETW | 0 | 0 |", "tags": ["filter", "aggregation"], "difficulty": "medium"}
{"qid": "Q38", "question_zh": "本月IPO事件的总佣金、手续费和保证金利息是多少?", "sql": "-- IPO相关费用汇总 (2026年4月)\nSELECT \n 'IPO Commission' AS FeeType,\n SUM(ip.SubscriptionAmount * 0.001) AS EstimatedFee\nFROM MCInstrumentIPODetail ip\nWHERE YEAR(ip.CreatedOn) = 2026\n AND MONTH(ip.CreatedOn) = 4;", "schema_info": {"tables": {"MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": []}, "explanation": "- IPO相关费用分散在多个表中\n- 需要关联 `BCAccountInstrument` 获取IPO交易费用", "question_en": "What are the total commission, handling fees, and margin interest for IPO events this month?", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["margin", "aggregation", "filter", "interest"], "difficulty": "easy"}
{"qid": "Q44", "question_zh": "本月收到/支付的利息金额是多少(如客户借款利息和存款利息)?", "sql": "-- 本月利息收支汇总 (2026年4月)\nSELECT \n SUM(AccruedCreditInterest) AS CreditInterest,\n SUM(AccruedDebitInterest) AS DebitInterest,\n SUM(AccruedCreditInterest) - SUM(AccruedDebitInterest) AS NetInterest\nFROM BCAccountCash;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `BCAccountCash` 记录账户现金和利息信息\n- `AccruedCreditInterest` 应计存款利息", "question_en": "What is the interest amount received/paid this month (e.g., client debit interest and credit interest)?", "rating": 7, "execution_result": null, "result_note": "| CreditInterest | DebitInterest | NetInterest |\n|----------------|---------------|-------------|\n| 464.15 | 2,022.70 | -1,558.55 |", "tags": ["account", "aggregation", "interest"], "difficulty": "easy"}
{"qid": "Q45", "question_zh": "不同经纪商(如非中央结算系统持仓)的客户总持仓是多少?", "sql": "-- 按托管位置统计持仓(非CCASS)\nSELECT \n loc.LocationID,\n loc.Name AS LocationName,\n COUNT(DISTINCT bi.AccountID) AS AccountCount,\n SUM(bi.Settled) AS TotalQuantity,\n SUM(bi.CostAmount) AS TotalCostAmount\nFROM BCAccountLocationInstrument bi\nINNER JOIN MCLocation loc ON bi.LocationID = loc.LocationID\nWHERE loc.CCASSFlag = 'N'\nGROUP BY loc.LocationID, loc.Name\nORDER BY TotalQuantity DESC;", "schema_info": {"tables": {"BCAccountLocationInstrument": {"alias": "bi", "columns": []}, "MCLocation": {"alias": "loc", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.LocationID = loc.LocationID"}]}, "explanation": "- `BCAccountLocationInstrument` 记录按托管位置分类的持仓\n- `MCLocation` 存储托管位置信息", "question_en": "What is the total client holding at different broker firms (e.g., non-CCASS locations)?", "rating": 7, "execution_result": null, "result_note": "当前查询需要验证 Location 表关联", "tags": ["join", "ordering", "holding", "broker", "filter", "account", "aggregation"], "difficulty": "hard"}
{"qid": "Q46", "question_zh": "支付给其他经纪商的佣金是多少?", "sql": "-- 查询支付给其他经纪商的佣金\nSELECT \n b.BrokerID,\n b.Name AS BrokerName,\n SUM(bc.Commission) AS TotalCommission,\n SUM(bc.Consideration) AS TotalConsideration\nFROM MCBroker b\nINNER JOIN BCBrokerCash bc ON b.BrokerID = bc.BrokerID\nWHERE bc.Commission > 0\nGROUP BY b.BrokerID, b.Name\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCBroker": {"alias": "b", "columns": []}, "BCBrokerCash": {"alias": "bc", "columns": []}}, "joins": [{"type": "INNER", "on": "b.BrokerID = bc.BrokerID"}]}, "explanation": "- `MCBroker` 存储经纪商信息\n- `BCBrokerCash` 可能包含经纪商现金和佣金数据", "question_en": "How much commission has been paid to other brokers?", "rating": 6, "execution_result": null, "result_note": "当前查询需要验证经纪商佣金表关联", "tags": ["join", "ordering", "broker", "filter", "aggregation"], "difficulty": "hard"}
{"qid": "Q47", "question_zh": "今日/指定日期发放了多少份日结单或月结单?", "sql": "-- 查询报表发放统计 (2026-04-02)\nSELECT \n 'Daily Statement' AS StatementType,\n COUNT(*) AS StatementCount\nFROM MCAccount\nWHERE LastDailyStatementDate = '2026-04-02'\nUNION ALL\nSELECT \n 'Monthly Statement' AS StatementType,\n COUNT(*) AS StatementCount\nFROM MCAccount\nWHERE LastMonthlyStatementDate = '2026-04-02';", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 记录账户报表发送日期\n- `LastDailyStatementDate` 最近日结单发送日期", "question_en": "How many daily or monthly statements were issued today / on a specific date?", "rating": 9, "execution_result": null, "result_note": "", "tags": ["union", "filter", "aggregation"], "difficulty": "hard"}
{"qid": "Q49", "question_zh": "本月、本季度和今年分别开了多少账户?", "sql": "-- 开户统计 (2026年4月)\nSELECT \n COUNT(CASE WHEN MONTH(OpenDate) = 4 AND YEAR(OpenDate) = 2026 THEN 1 END) AS April2026,\n COUNT(CASE WHEN DATEPART(QUARTER, OpenDate) = 2 AND YEAR(OpenDate) = 2026 THEN 1 END) AS Q2_2026,\n COUNT(CASE WHEN YEAR(OpenDate) = 2026 THEN 1 END) AS Year2026,\n COUNT(*) AS TotalAccounts,\n MIN(OpenDate) AS EarliestOpenDate,\n MAX(OpenDate) AS LatestOpenDate\nFROM MCAccount\nWHERE OpenDate IS NOT NULL;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.OpenDate` 账户开户日期\n- 按月、季度、年分别统计新开户数量", "question_en": "How many accounts were opened this month, this quarter, and this year?", "rating": 9, "execution_result": null, "result_note": "| April2026 | Q2_2026 | Year2026 | TotalAccounts | EarliestOpenDate | LatestOpenDate |\n|-----------|---------|----------|---------------|------------------|----------------|\n| 0 | 0 | 0 | 1,951 | 1993-03-05 | 2025-10-16 |", "tags": ["account", "limit", "filter", "aggregation"], "difficulty": "easy"}
+3
View File
@@ -0,0 +1,3 @@
{"qid": "Q1", "question_zh": "按对手方列出截至[日期]的所有未结算交易。", "sql": "-- 按对手方统计截至 2026-04-02 的未结算交易\n-- 使用 TSBBrokerContract(经纪商合约表),按 BrokerID(对手方经纪商)分组\n-- SettleStatus='U' 表示未结算;CashSettleDate <= '2026-04-02' 筛选截至日\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n COUNT(*) AS UnsettledTradeCount,\n SUM(b.SettleQuantity) AS TotalUnsettledQty,\n SUM(b.SettleAmount) AS TotalUnsettledAmount,\n MIN(b.BuySell) + '~' + MAX(b.BuySell) AS BuySellRange,\n MIN(b.CashSettleDate) AS EarliestSettleDate,\n MAX(b.CashSettleDate) AS LatestSettleDate\nFROM TSBBrokerContract b\nLEFT JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.SettleStatus = 'U'\n AND b.CashSettleDate <= '2026-04-02'\nGROUP BY b.BrokerID, m.Name\nORDER BY TotalUnsettledAmount DESC;", "schema_info": {"tables": {"TSBBrokerContract": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "LEFT", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `TSBBrokerContract` 是经纪商/对手方合约表,记录与外部对手方的交易合约,`BrokerID` 即对手方标识\n- `SettleStatus = 'U'` 表示未结算;`CashSettleDate <= '2026-04-02'` 筛选截至日未结清的合约\n- 关联 `MCBroker` 获取对手方经纪商名称\n- 按 `BrokerID` 分组汇总未结算数量和金额", "question_en": "Show all unsettled trades as of [date] grouped by counterparty.", "rating": 9, "execution_result": null, "result_note": "| BrokerID | BrokerName | UnsettledTradeCount | TotalUnsettledQty | TotalUnsettledAmount | BuySellRange | EarliestSettleDate | LatestSettleDate |\n|----------|-----------|---------------------|-------------------|---------------------|--------------|---------------------|-------------------|\n| CCASS | CCASS | 622 | 40,459,253 | 44,173,571.06 | B~S | 2025-07-30 | 2026-04-02 |\n\n> **注**:CCASS(Hong Kong Securities Clearing Company Limited)是香港交易所的中央结算机构,作为交易所交易的核心对手方。622笔未结算合约均为 HKEX 市场。", "tags": ["join", "ordering", "broker", "filter", "trade", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q45", "question_zh": "不同经纪商(如非中央结算系统持仓)的客户总持仓是多少?", "sql": "-- 按托管位置统计持仓(非CCASS)\nSELECT \n loc.LocationID,\n loc.Name AS LocationName,\n COUNT(DISTINCT bi.AccountID) AS AccountCount,\n SUM(bi.Settled) AS TotalQuantity,\n SUM(bi.CostAmount) AS TotalCostAmount\nFROM BCAccountLocationInstrument bi\nINNER JOIN MCLocation loc ON bi.LocationID = loc.LocationID\nWHERE loc.CCASSFlag = 'N'\nGROUP BY loc.LocationID, loc.Name\nORDER BY TotalQuantity DESC;", "schema_info": {"tables": {"BCAccountLocationInstrument": {"alias": "bi", "columns": []}, "MCLocation": {"alias": "loc", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.LocationID = loc.LocationID"}]}, "explanation": "- `BCAccountLocationInstrument` 记录按托管位置分类的持仓\n- `MCLocation` 存储托管位置信息", "question_en": "What is the total client holding at different broker firms (e.g., non-CCASS locations)?", "rating": 7, "execution_result": null, "result_note": "当前查询需要验证 Location 表关联", "tags": ["join", "ordering", "holding", "broker", "filter", "account", "aggregation"], "difficulty": "hard"}
{"qid": "Q46", "question_zh": "支付给其他经纪商的佣金是多少?", "sql": "-- 查询支付给其他经纪商的佣金\nSELECT \n b.BrokerID,\n b.Name AS BrokerName,\n SUM(bc.Commission) AS TotalCommission,\n SUM(bc.Consideration) AS TotalConsideration\nFROM MCBroker b\nINNER JOIN BCBrokerCash bc ON b.BrokerID = bc.BrokerID\nWHERE bc.Commission > 0\nGROUP BY b.BrokerID, b.Name\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCBroker": {"alias": "b", "columns": []}, "BCBrokerCash": {"alias": "bc", "columns": []}}, "joins": [{"type": "INNER", "on": "b.BrokerID = bc.BrokerID"}]}, "explanation": "- `MCBroker` 存储经纪商信息\n- `BCBrokerCash` 可能包含经纪商现金和佣金数据", "question_en": "How much commission has been paid to other brokers?", "rating": 6, "execution_result": null, "result_note": "当前查询需要验证经纪商佣金表关联", "tags": ["join", "ordering", "broker", "filter", "aggregation"], "difficulty": "hard"}
+5
View File
@@ -0,0 +1,5 @@
{"qid": "Q6", "question_zh": "所有货币的客户现金总余额是多少?", "sql": "-- 按货币统计客户现金余额\nSELECT \n CurrencyID,\n COUNT(DISTINCT AccountID) AS AccountCount,\n SUM(Settled) AS TotalSettledBalance,\n SUM(AccruedCreditInterest) AS TotalCreditInterest,\n SUM(AccruedDebitInterest) AS TotalDebitInterest,\n SUM(Settled) + SUM(AccruedCreditInterest) - SUM(AccruedDebitInterest) AS NetBalance\nFROM BCAccountCash\nGROUP BY CurrencyID\nORDER BY NetBalance DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `BCAccountCash` 记录账户现金余额\n- `Settled` 已结算余额\n- `AccruedCreditInterest` 应计存款利息\n- `AccruedDebitInterest` 应计借款利息", "question_en": "What is the total client cash balance across all currencies?", "rating": 9, "execution_result": null, "result_note": "| CurrencyID | AccountCount | TotalSettledBalance | NetBalance |\n|------------|-------------|--------------------|------------|\n| HKD | 2,906 | 52,195,305.77 | 52,195,305.77 |\n| TWD | 2 | -27,676.60 | -27,676.60 |\n| USD | 175 | 0 | 0 |\n| CNY | 95 | 0 | 0 |\n| GBP | 1 | 0 | 0 |", "tags": ["ordering", "account", "cash", "aggregation"], "difficulty": "medium"}
{"qid": "Q7", "question_zh": "今日结算后现金余额为负的账户列表。", "sql": "-- 查询现金余额为负的账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.Settled AS CashBalance,\n c.UnderdueCheque,\n c.BankAvailableBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.Settled < 0\nORDER BY c.Settled ASC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash.Settled` 表示已结算现金余额\n- 负数表示账户透支\n- 关联 `MCAccount` 获取账户名称", "question_en": "List accounts with negative cash balance after today's settlement.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | CurrencyID | CashBalance |\n|-----------|------------|------------|-------------|\n| M050009 | NG SUN SHU*** | HKD | -4,678,978.42 |\n| P050667 | WONG YIM HUNG | HKD | -780,196.94 |\n| M050521 | LO CHUN YIP | HKD | -290,487.54 |\n\n(共55个账户现金余额为负)", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q21", "question_zh": "截至昨日的客户借方余额应计利息是多少?", "sql": "-- 查询客户借方余额应计利息 (截至2026-04-01)\nSELECT \n SUM(AccruedDebitInterest) AS TotalDebitInterestAccrued,\n SUM(AccruedCreditInterest) AS TotalCreditInterestAccrued,\n SUM(AccruedDebitInterest) - SUM(AccruedCreditInterest) AS NetDebitInterest,\n COUNT(DISTINCT AccountID) AS AccountCount\nFROM BCAccountCash\nWHERE AccruedDebitInterest > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `AccruedDebitInterest` 借款应计利息\n- `AccruedCreditInterest` 存款应计利息", "question_en": "What is the interest accrued on client debit balances as of yesterday?", "rating": 8, "execution_result": null, "result_note": "| TotalDebitInterestAccrued | TotalCreditInterestAccrued | NetDebitInterest | AccountCount |\n|---------------------------|---------------------------|-----------------|-------------|\n| 2,022.70 | 464.15 | 1,558.55 | 55 |", "tags": ["filter", "account", "interest", "cash", "aggregation"], "difficulty": "hard"}
{"qid": "Q22", "question_zh": "列出今日所有公司账户与客户账户之间的现金划转。", "sql": "-- 查询公司账户与客户账户现金划转 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n a.AccountType,\n c.CurrencyID,\n c.TodayIn AS CashInflow,\n c.TodayOut AS CashOutflow,\n c.Settled AS CurrentBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE (c.TodayIn > 0 OR c.TodayOut > 0)\nORDER BY c.TodayIn + c.TodayOut DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- 公司账户与客户账户通过 `AccountType` 区分\n- `TodayIn/TodayOut` 记录现金流动", "question_en": "List all cash movements between house and client accounts today.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q41", "question_zh": "列出今日执行的所有现金划转。", "sql": "-- 今日现金变动汇总 (固定日期: 2026-04-02)\nSELECT \n b.AccountID,\n a.Name AS AccountName,\n b.TodayIn AS CashIn,\n b.TodayOut AS CashOut,\n b.BankAvailableBalance\nFROM BCAccountCash b\nINNER JOIN MCAccount a ON b.AccountID = a.AccountID\nWHERE b.TodayIn > 0 OR b.TodayOut > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "b", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "b.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash` 记录账户现金变动\n- `TodayIn` 今日现金流入", "question_en": "List all cash movements performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "filter", "cash"], "difficulty": "easy"}
@@ -0,0 +1,3 @@
{"qid": "Q8", "question_zh": "明天生效的公司行动涉及哪些证券?", "sql": "-- 查询明日生效的公司行动 (固定日期: 2026-04-03)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.BalanceDate AS EffectiveDate,\n e.BalanceExDate AS ExDate,\n e.Remark AS Description\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE (e.BalanceDate = '2026-04-03' OR e.BalanceExDate = '2026-04-03')\n AND e.State = 'A';", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录权益分派信息\n- `BalanceDate` 权益登记日期\n- `BalanceExDate` 除权日期", "question_en": "Which instruments have corporate actions effective tomorrow?", "rating": 8, "execution_result": null, "result_note": "当前查询无结果(2026-04-03无公司行动)", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q20", "question_zh": "哪些公司行动的选择指令需在今日结束前提交?", "sql": "-- 查询今日截止的公司行动选择 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.ElectionPeriodTo AS Deadline,\n e.ElectionOptionFlag,\n e.Remark AS Description\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.ElectionPeriodTo = '2026-04-02'\n AND e.ElectionOptionFlag = 'Y'\n AND e.State = 'A';", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `ElectionPeriodTo` 选择截止日期\n- `ElectionOptionFlag = 'Y'` 需要选择", "question_en": "Which corporate action elections are due by end of day?", "rating": 8, "execution_result": null, "result_note": "当前查询无今日截止的选择", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q39", "question_zh": "列出今日需要执行的公司行动(如权益分派)。", "sql": "-- 查询今日生效的公司行动 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.MarketID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.BalanceDate,\n e.BalanceExDate,\n e.Remark,\n e.State\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.State = 'A'\n AND (\n e.BalanceDate = '2026-04-02'\n OR e.BalanceExDate = '2026-04-02'\n OR e.AutoHoldDate = '2026-04-02'\n OR e.AutoDeductDate = '2026-04-02'\n );", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录所有权益分派信息\n- `BalanceDate` 权益登记日期", "question_en": "List corporate actions (e.g., entitlements) that need to be performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
@@ -0,0 +1,2 @@
{"qid": "Q27", "question_zh": "列出所有超过3天的暂记账户分录。", "sql": "-- 查询超过3天的暂记账户分录 (2026-04-02)\n-- 说明:TCAccountCashMovement 是现金流水表\n-- NeedHoldFlag='Y' 表示暂记分录\n-- Amount - ReleasedAmount 表示未释放金额(暂记余额)\n-- 筛选未释放且超过3天的暂记分录\nSELECT \n cm.AccountID,\n cm.MovementID,\n cm.ValueDate,\n cm.CurrencyID,\n cm.Amount - ISNULL(cm.ReleasedAmount, 0) AS PendingBalance,\n cm.Remark,\n DATEDIFF(DAY, cm.ValueDate, '2026-04-02') AS DaysOutstanding\nFROM TCAccountCashMovement cm\nWHERE cm.NeedHoldFlag = 'Y'\n AND cm.Amount - ISNULL(cm.ReleasedAmount, 0) != 0\n AND DATEDIFF(DAY, cm.ValueDate, '2026-04-02') > 3\nORDER BY DaysOutstanding DESC, PendingBalance DESC;", "schema_info": {"tables": {"TCAccountCashMovement": {"alias": "cm", "columns": []}}, "joins": []}, "explanation": "- `TCAccountCashMovement` 存储现金流水记录\n- `NeedHoldFlag = 'Y'` 标识暂记(待确认)分录\n- `Amount - ReleasedAmount` 计算未释放的暂记余额\n- `DATEDIFF` 计算距今天数\n- `DATEDIFF > 3` 筛选超过3天的记录", "question_en": "List all suspense account entries older than 3 days.", "rating": 9, "execution_result": null, "result_note": "**查询结果:0条记录**\n\n当前没有超过3天未释放的暂记账户分录。所有暂记分录的 ReleasedAmount = Amount,已全部释放。", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q29", "question_zh": "列出后台系统中所有活跃用户账户及其最后登录日期。", "sql": "-- 查询活跃用户及其登录情况\nSELECT \n u.UserID,\n u.Name AS UserName,\n u.Status,\n u.LogonEnableFlag,\n u.LastLogonTime,\n u.BranchID,\n CASE u.CompanyAEFlag WHEN 'Y' THEN '公司经纪' ELSE '个人' END AS AEType,\n CASE \n WHEN u.LastLogonTime >= DATEADD(DAY, -7, GETDATE()) THEN '近7天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -30, GETDATE()) THEN '近30天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -90, GETDATE()) THEN '近90天活跃'\n ELSE '长期未登录'\n END AS ActivityStatus\nFROM MCUser u\nWHERE u.State = 'A'\n AND u.LogonEnableFlag = 'Y'\nORDER BY u.LastLogonTime DESC;", "schema_info": {"tables": {"MCUser": {"alias": "u", "columns": []}}, "joins": []}, "explanation": "- `MCUser` 存储用户信息\n- `LastLogonTime` 最后登录时间", "question_en": "List all active user accounts in the back office system with last login date.", "rating": 9, "execution_result": null, "result_note": "| UserID | UserName | Status | LogonEnableFlag | LastLogonTime | ActivityStatus |\n|--------|----------|--------|-----------------|---------------|----------------|\n| SUPPORT | SUPPORT | N | Y | 2026-04-08 | 近7天活跃 |\n| ROSANNA | ROSANNA | N | Y | 2025-10-21 | 长期未登录 |\n| SING | WONG LO SING | N | Y | 2025-10-21 | 长期未登录 |\n| LEONNG | LEON NG | N | Y | 2025-10-21 | 长期未登录 |", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
+1
View File
@@ -0,0 +1 @@
{"qid": "Q26", "question_zh": "本月各交易所的结算费用明细如何?", "sql": "-- 按交易所统计结算费用 (2026年4月)\n-- 说明:BCAccountInstrument 表中 TotalBoughtFee/TotalSoldFee 是持仓级别的交易费用字段\n-- LastTransactionDate 表示该持仓最后交易日期\n-- 查询逻辑:筛选最后交易日期在本月内的持仓记录,按交易所汇总交易费用\nSELECT \n bi.MarketID,\n m.MarketName,\n SUM(bi.TotalBoughtFee) AS TotalBuyFee,\n SUM(bi.TotalSoldFee) AS TotalSellFee,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalSettlementFee,\n COUNT(DISTINCT bi.AccountID) AS TradingAccountCount\nFROM BCAccountInstrument bi\nINNER JOIN MCMarket m ON bi.MarketID = m.MarketID\nWHERE bi.LastTransactionDate >= '2026-04-01' AND bi.LastTransactionDate < '2026-05-01'\nGROUP BY bi.MarketID, m.MarketName\nORDER BY TotalSettlementFee DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCMarket": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.MarketID = m.MarketID"}]}, "explanation": "- `BCAccountInstrument` 存储持仓级别信息,包含各持仓的交易费用累计\n- `MCMarket` 存储市场信息,提供市场名称\n- `LastTransactionDate` 用于过滤本月有交易的持仓记录\n- 按市场分组汇总结算费用", "question_en": "What is the breakdown of settlement fees by exchange for this month?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "trade", "aggregation", "date_range"], "difficulty": "hard"}
@@ -0,0 +1 @@
{"qid": "Q3", "question_zh": "今日结算使用的汇率是多少?", "sql": "-- 查询汇率类型列表 (固定日期: 2026-04-02)\nSELECT \n ExchangeRateID, \n Name, \n NameEx\nFROM HCExchangeRate\nWHERE ValueDate = '2026-04-02'\nORDER BY ExchangeRateID;", "schema_info": {"tables": {"HCExchangeRate": {"alias": "HCExchangeRate", "columns": []}}, "joins": []}, "explanation": "- `HCExchangeRate` 存储汇率类型定义\n- `HCExchangeRateDetail` 存储各货币对的汇率值\n- 两个表通过 `ExchangeRateID` + `ValueDate` 关联\n- `ExchangeRateDirection` = 'D' 表示直接汇率", "question_en": "What are the currency exchange rates used for today's settlement?", "rating": 9, "execution_result": null, "result_note": "", "tags": ["exchange_rate", "filter", "ordering"], "difficulty": "easy"}
+45
View File
@@ -0,0 +1,45 @@
{"qid": "Q1", "question_zh": "按对手方列出截至[日期]的所有未结算交易。", "sql": "-- 按对手方统计截至 2026-04-02 的未结算交易\n-- 使用 TSBBrokerContract(经纪商合约表),按 BrokerID(对手方经纪商)分组\n-- SettleStatus='U' 表示未结算;CashSettleDate <= '2026-04-02' 筛选截至日\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n COUNT(*) AS UnsettledTradeCount,\n SUM(b.SettleQuantity) AS TotalUnsettledQty,\n SUM(b.SettleAmount) AS TotalUnsettledAmount,\n MIN(b.BuySell) + '~' + MAX(b.BuySell) AS BuySellRange,\n MIN(b.CashSettleDate) AS EarliestSettleDate,\n MAX(b.CashSettleDate) AS LatestSettleDate\nFROM TSBBrokerContract b\nLEFT JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.SettleStatus = 'U'\n AND b.CashSettleDate <= '2026-04-02'\nGROUP BY b.BrokerID, m.Name\nORDER BY TotalUnsettledAmount DESC;", "schema_info": {"tables": {"TSBBrokerContract": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "LEFT", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `TSBBrokerContract` 是经纪商/对手方合约表,记录与外部对手方的交易合约,`BrokerID` 即对手方标识\n- `SettleStatus = 'U'` 表示未结算;`CashSettleDate <= '2026-04-02'` 筛选截至日未结清的合约\n- 关联 `MCBroker` 获取对手方经纪商名称\n- 按 `BrokerID` 分组汇总未结算数量和金额", "question_en": "Show all unsettled trades as of [date] grouped by counterparty.", "rating": 9, "execution_result": null, "result_note": "| BrokerID | BrokerName | UnsettledTradeCount | TotalUnsettledQty | TotalUnsettledAmount | BuySellRange | EarliestSettleDate | LatestSettleDate |\n|----------|-----------|---------------------|-------------------|---------------------|--------------|---------------------|-------------------|\n| CCASS | CCASS | 622 | 40,459,253 | 44,173,571.06 | B~S | 2025-07-30 | 2026-04-02 |\n\n> **注**:CCASS(Hong Kong Securities Clearing Company Limited)是香港交易所的中央结算机构,作为交易所交易的核心对手方。622笔未结算合约均为 HKEX 市场。", "tags": ["join", "ordering", "broker", "filter", "trade", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q2", "question_zh": "列出今日所有客户账户之间的股票转移记录。", "sql": "-- 查询今日客户账户间股票转移(参考日期:2026-04-02)\n-- 使用 TSBAccountInstrumentMovement,MovementType='T' 表示账户间转移\n-- ValueDate 为转移生效日期,关联 MCInstrument 获取证券名称\nSELECT \n m.MovementID,\n m.AccountID AS FromAccountID,\n m.TransferToAccountID,\n m.InstrumentID,\n i.Name AS InstrumentSymbol,\n m.MovementType,\n m.Quantity AS TransferQuantity,\n m.ValueDate AS TransferDate\nFROM TSBAccountInstrumentMovement m\nLEFT JOIN MCInstrument i ON m.InstrumentID = i.InstrumentID\nWHERE m.MovementType = 'T'\n AND m.ValueDate = '2026-04-02'\nORDER BY m.ValueDate;", "schema_info": {"tables": {"TSBAccountInstrumentMovement": {"alias": "m", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "LEFT", "on": "m.InstrumentID = i.InstrumentID"}]}, "explanation": "- `TSBAccountInstrumentMovement` 是持仓变动流水表,记录所有证券变动事件\n- `MovementType = 'T'`(Transfer)特指**账户间股票转移**,对应 `TransferToAccountID` 记录目标账户\n- `ValueDate` 是转移生效日期,可按日期过滤\n- 关联 `MCInstrument` 获取证券代码/名称\n- 注意:`BCAccountInstrument` 的 `TodayIn/TodayOut` 是**实时快照**,不带历史日期维度,不能用于查历史转移", "question_en": "List all stock transfers between client accounts performed today.", "rating": 9, "execution_result": null, "result_note": "当前查询无结果(测试环境中 `TSBAccountInstrumentMovement` 的 `MovementType='T'` 最新记录为 2025-10-21,无 2026-04-02 的账户间转移数据)", "tags": ["join", "ordering", "filter", "account", "left_join"], "difficulty": "hard"}
{"qid": "Q3", "question_zh": "今日结算使用的汇率是多少?", "sql": "-- 查询汇率类型列表 (固定日期: 2026-04-02)\nSELECT \n ExchangeRateID, \n Name, \n NameEx\nFROM HCExchangeRate\nWHERE ValueDate = '2026-04-02'\nORDER BY ExchangeRateID;", "schema_info": {"tables": {"HCExchangeRate": {"alias": "HCExchangeRate", "columns": []}}, "joins": []}, "explanation": "- `HCExchangeRate` 存储汇率类型定义\n- `HCExchangeRateDetail` 存储各货币对的汇率值\n- 两个表通过 `ExchangeRateID` + `ValueDate` 关联\n- `ExchangeRateDirection` = 'D' 表示直接汇率", "question_en": "What are the currency exchange rates used for today's settlement?", "rating": 9, "execution_result": null, "result_note": "", "tags": ["exchange_rate", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q4", "question_zh": "哪些券商尚有未履行的交收义务?", "sql": "-- 查询有未履行交收义务的经纪商(截至 2026-04-02)\n-- Settled < 0 表示经纪商欠我们的现金(未履行交收义务)\n-- 注意:BCBrokerCash.Settled 是经纪商在我们账户的已结算现金余额,负数=经纪商欠款\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n b.CurrencyID,\n b.Settled AS OwedToUsAmount,\n ABS(b.Settled) AS OutstandingAmount\nFROM BCBrokerCash b\nINNER JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.Settled < 0\nORDER BY ABS(b.Settled) DESC;", "schema_info": {"tables": {"BCBrokerCash": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `BCBrokerCash` 记录经纪商在我们账户的结算现金,`Settled < 0` = 经纪商欠我们(未履行交收义务)\n- 关联 `MCBroker` 获取经纪商名称\n- 按欠款金额降序排列,优先处理大额欠款", "question_en": "Which brokers have outstanding delivery obligations to us?", "rating": 8, "execution_result": null, "result_note": "| BrokerID | BrokerName | CurrencyID | OwedToUsAmount | OutstandingAmount |\n|----------|-----------|------------|-----------------|-------------------|\n| CCASS | CCASS | CNY | -52,680.00 | 52,680.00 |\n| CCASS | CCASS | USD | -90.00 | 90.00 |\n\n> 注:CCASS 欠我们的结算现金(CNY 52,680 + USD 90)。HKD 余额为正(+4,202,811.87)表示我们欠 CCASS,不属于\"未履行交收义务\"范畴。", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q5", "question_zh": "列出今日发出的所有追收保证金通知及其回复状态。", "sql": "-- 查询今日追缴保证金记录 (参考日期: 2026-04-02)\n-- 使用 MCAccount 的账户级追缴字段(CallForDepositDate = 追缴通知发出日期)\n-- 注意:HCAccountMarginCallForDeposit 是追缴每日快照表,不含\"通知发出日\"字段\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n a.CallForDeposit AS CallAmount,\n a.CallForDepositDate AS IssueDate,\n a.CallForDepositDays AS OverdueDays\nFROM MCAccount a\nWHERE a.CallForDepositDate = '2026-04-02'\nORDER BY a.CallForDeposit DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.CallForDepositDate` = 追缴通知发出日期,`CallForDeposit` = 追缴金额\n- `CallForDeposit < 0` 表示已结清;如查活跃追缴,应筛选 `CallForDeposit > 0`\n- `HCAccountMarginCallForDeposit` 是追缴每日历史快照,不适合查询\"今日发出的通知\"\n- `CallStatus` 字段在 `HCAccountMarginCallForDeposit` 中不存在", "question_en": "Show all margin calls issued today and their response status.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果(测试环境中 MCAccount 的 `CallForDepositDate` 最新到 2025-10-31,2026-04-02 无追缴通知记录)\n\n> 注:`MCAccount.CallForDeposit` 当前所有值均为负数(已结清的追缴金额),无活跃追缴记录。", "tags": ["margin", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q7", "question_zh": "今日结算后现金余额为负的账户列表。", "sql": "-- 查询现金余额为负的账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.Settled AS CashBalance,\n c.UnderdueCheque,\n c.BankAvailableBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.Settled < 0\nORDER BY c.Settled ASC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash.Settled` 表示已结算现金余额\n- 负数表示账户透支\n- 关联 `MCAccount` 获取账户名称", "question_en": "List accounts with negative cash balance after today's settlement.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | CurrencyID | CashBalance |\n|-----------|------------|------------|-------------|\n| M050009 | NG SUN SHU*** | HKD | -4,678,978.42 |\n| P050667 | WONG YIM HUNG | HKD | -780,196.94 |\n| M050521 | LO CHUN YIP | HKD | -290,487.54 |\n\n(共55个账户现金余额为负)", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q8", "question_zh": "明天生效的公司行动涉及哪些证券?", "sql": "-- 查询明日生效的公司行动 (固定日期: 2026-04-03)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.BalanceDate AS EffectiveDate,\n e.BalanceExDate AS ExDate,\n e.Remark AS Description\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE (e.BalanceDate = '2026-04-03' OR e.BalanceExDate = '2026-04-03')\n AND e.State = 'A';", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录权益分派信息\n- `BalanceDate` 权益登记日期\n- `BalanceExDate` 除权日期", "question_en": "Which instruments have corporate actions effective tomorrow?", "rating": 8, "execution_result": null, "result_note": "当前查询无结果(2026-04-03无公司行动)", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q9", "question_zh": "今日预计收到哪些股息?", "sql": "-- 查询今日预计收到的股息 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceDate AS PaymentDate,\n e.BalanceType,\n e.Remark AS DividendDetails\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.BalanceDate = '2026-04-02'\n AND e.BalanceType = 'C'\n AND e.State = 'A'\nORDER BY i.Name;", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录所有权益分派\n- `BalanceType = 'C'` 表示现金股息\n- `BalanceDate` 股息支付日期", "question_en": "What dividends are expected to be received today?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q10", "question_zh": "列出所有进行中IPO的待缴申购金额。", "sql": "-- 查询进行中IPO的待缴金额\nSELECT \n ip.InstrumentID,\n i.Name AS InstrumentName,\n i.State AS InstrumentStatus,\n ip.SubscriptionAmount,\n ip.SubscriptionPrice,\n ip.Quantity AS SubscriptionLot,\n ip.CreatedOn AS SubscriptionDate,\n ip.State AS SubscriptionStatus\nFROM MCInstrumentIPODetail ip\nINNER JOIN MCInstrument i ON ip.InstrumentID = i.InstrumentID\nWHERE ip.State = 'A'\n AND i.State = 'A'\nORDER BY ip.CreatedOn DESC;", "schema_info": {"tables": {"MCInstrumentIPODetail": {"alias": "ip", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "ip.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MCInstrumentIPODetail` 记录IPO认购详情\n- `SubscriptionAmount` 申购金额\n- `State = 'A'` 表示进行中", "question_en": "Show all pending subscription amounts for ongoing IPOs.", "rating": 8, "execution_result": null, "result_note": "| InstrumentID | InstrumentName | SubscriptionAmount | SubscriptionPrice | Quantity |\n|--------------|----------------|-------------------|-------------------|----------|\n| 02259 | HKEX | 7,231.19 | 36.16 | 100 |\n| 02259 | HKEX | 14,462.40 | 36.16 | 200 |\n\n> 注:MCInstrumentIPODetail 共 586 条进行中 IPO 记录(State='A'),以上为示例行。", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q11", "question_zh": "哪些客户尚未缴纳IPO申购款?", "sql": "-- 查询未缴纳IPO申购款的账户\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.TotalBoughtQuantity AS SubscriptionLot,\n bi.TotalBoughtConsideration AS SubscriptionAmount\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nINNER JOIN MCInstrumentIPODetail ip ON bi.InstrumentID = ip.InstrumentID\nWHERE ip.State = 'A'\n AND bi.TotalBoughtConsideration > 0\n AND bi.TotalBoughtFee = 0\nORDER BY bi.TotalBoughtConsideration DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}, "MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}, {"type": "INNER", "on": "bi.InstrumentID = ip.InstrumentID"}]}, "explanation": "- 通过比对买卖数量和手续费判断是否缴款\n- `TotalBoughtConsideration > 0` 有认购\n- `TotalBoughtFee = 0` 未支付手续费", "question_en": "Which clients have not yet paid their IPO subscription money?", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "ordering"], "difficulty": "hard"}
{"qid": "Q12", "question_zh": "本月累计的结算失败罚金是多少?", "sql": "-- 查询本月结算失败罚金 (2026年4月)\n-- 注意:BCAccountInstrument 无 FailedTradePenalty 字段,需另找结算罚金存储位置\n-- 目前未找到结算失败罚金字段,建议通过 TSBBrokerContract 或 BCBrokerCash 进一步排查\nSELECT \n COUNT(*) AS FailedTradeCount,\n MarketID\nFROM BCAccountInstrument\nWHERE YEAR(LastTransactionDate) = 2026\n AND MONTH(LastTransactionDate) = 4\nGROUP BY MarketID;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 无 `FailedTradePenalty` 字段,原始 SQL 会报错\n- `TSBBrokerContract` 或 `BCBrokerCash` 中可能存储结算相关费用,需进一步确认", "question_en": "What is the total failed trade penalty incurred this month?", "rating": 3, "execution_result": null, "result_note": "当前查询无结果(BCAccountInstrument 表无 FailedTradePenalty 字段,无法统计结算罚金)", "tags": ["filter", "aggregation"], "difficulty": "medium"}
{"qid": "Q13", "question_zh": "列出今日到期的所有股票借贷交易。", "sql": "-- 查询今日到期的股票借贷 (参考日期: 2026-04-02)\n-- MCMarket 表仅包含 HKEX/OSL/SETW,无独立借贷市场标识\n-- 股票借贷可能在持仓变动类型 HoldType 中标识,或在专门的 StockBorrowing 表中\n-- 此 SQL 按 DueBuy/DueSell 显示当前待交收证券,作为借贷合约的近似替代\nSELECT \n bi.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.DueBuy AS BorrowQuantity,\n bi.DueSell AS LoanQuantity,\n bi.DueBuy - bi.DueSell AS NetBorrow\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nWHERE bi.DueBuy > 0 OR bi.DueSell > 0;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}]}, "explanation": "- `DueBuy/DueSell` 表示待交收数量(借款买入/借出卖出),反映股票借贷待到期情况\n- `MCMarket` 表无 `MarketType='BORROW'` 标识,现有市场仅为 HKEX/OSL/SETW\n- 股票借贷详情可能存储在 `TSBAccountLoanContract` 或其他借贷专用表中,需业务确认", "question_en": "List all stock borrow/loan transactions due to settle today.", "rating": 5, "execution_result": null, "result_note": "当前查询无结果(BCAccountInstrument 中 DueBuy/DueSell 均为 0,无待交收证券)", "tags": ["join", "trade", "filter"], "difficulty": "medium"}
{"qid": "Q14", "question_zh": "列出已申请但尚未处理的客户提款请求。", "sql": "-- 查询待处理提款申请 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.TodayOut AS WithdrawalAmount,\n c.BankAvailableBalance AS AvailableBalance,\n c.State AS RecordStatus\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.TodayOut > 0\nORDER BY c.TodayOut DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `TodayOut` 今日计划支出\n- 待处理提款申请应体现在此字段", "question_en": "Show all client withdrawals requested but not yet processed.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q15", "question_zh": "本月应付给介绍经纪人的佣金返佣总额是多少?", "sql": "-- 查询本月应付返佣 (2026年4月)\n-- 注意:BCAccountInstrument 无 UpdatedAt 字段,用 LastTransactionDate 过滤本月有交易的账户\n-- 说明:TotalBoughtFee/TotalSoldFee 为历史累计字段,此处统计近期活跃账户的累计佣金供参考\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE YEAR(bi.LastTransactionDate) = 2026\n AND MONTH(bi.LastTransactionDate) = 4\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee + bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCRebateScheme` 可能存储返佣规则\n- 按AE汇总佣金", "question_en": "What is the total commission rebate payable to introducing brokers this month?", "rating": 6, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q16", "question_zh": "列出T+2交易缺少结算指令的账户。", "sql": "-- 查询T+2待交收但缺少指令的账户\n-- 注意:BCAccountInstrumentInstruction 表不存在,需改用 TSBSettlementInstruction\nSELECT \n bi.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.NextDayDueBuy AS T2DueBuy,\n bi.NextDayDueSell AS T2DueSell\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nWHERE (bi.NextDayDueBuy > 0 OR bi.NextDayDueSell > 0)\n AND NOT EXISTS (\n SELECT 1 FROM TSBSettlementInstruction si\n WHERE si.AccountOrBrokerID = bi.AccountID\n AND si.InstrumentID = bi.InstrumentID\n AND si.State IN ('P','A')\n );", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}, "TSBSettlementInstruction": {"alias": "si", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}]}, "explanation": "- `NextDayDueBuy/NextDayDueSell` T+2交收数量(次日到期)\n- `TSBSettlementInstruction` 是结算指令表,通过 `NOT EXISTS` 排除已有指令的记录\n- `BCAccountInstrumentInstruction` 表不存在,不能使用", "question_en": "Show accounts where settlement instruction is missing for T+2 trades.", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "trade"], "difficulty": "medium"}
{"qid": "Q17", "question_zh": "哪些客户已超过其信用额度?", "sql": "-- 查询超信用额度客户(使用 MarginLimit)\n-- 注意:MCAccount 无 CreditLimit 字段,应用 MarginLimit\nSELECT \n AccountID,\n Name AS AccountName,\n MarginLimit,\n MarketValue,\n MarginLimit - MarketValue AS AvailableCredit,\n CASE \n WHEN MarketValue > MarginLimit THEN '超额'\n WHEN MarketValue > MarginLimit * 0.8 THEN '接近限额'\n ELSE '正常'\n END AS Status\nFROM MCAccount\nWHERE MarginLimit > 0\n AND MarketValue > MarginLimit * 0.8\nORDER BY (MarketValue - MarginLimit) DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.MarginLimit` 保证金/信用限额(注意:无 `CreditLimit` 字段)\n- `MCAccount.MarketValue` 持仓市值\n- `MarginBLimit` 是单独借款限额,注意区分", "question_en": "Which clients have exceeded their credit limit?", "rating": 7, "execution_result": null, "result_note": "当前查询无超限客户", "tags": ["account", "limit", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q18", "question_zh": "今日收到的未清算支票总额是多少?", "sql": "-- 查询未清算支票 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.UnderdueCheque AS OverdueCheque,\n c.NextDayDueCheque AS PendingCheque,\n c.UnderdueCheque + c.NextDayDueCheque AS TotalUncleared\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE (c.UnderdueCheque > 0 OR c.NextDayDueCheque > 0) -- 注意:BCAccountCash 无这两个字段,需确认实际表\nORDER BY TotalUncleared DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash` 无 `UnderdueCheque` / `NextDayDueCheque` 字段,需业务确认支票数据存储位置", "question_en": "What is the total amount of uncleared cheques received today?", "rating": 4, "execution_result": null, "result_note": "当前查询无未清算支票", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q19", "question_zh": "列出今日起保证金比例发生变动的所有证券。", "sql": "-- 查询保证金比例变动的证券 (固定日期: 2026-04-02)\nSELECT \n i.InstrumentID,\n i.Name AS InstrumentName,\n i.MarginPercentage AS CurrentMarginRatio,\n i.MarginChangeDate\nFROM MCInstrument i\nWHERE i.MarginChangeDate = '2026-04-02'\nORDER BY i.MarginPercentage DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "i", "columns": []}}, "joins": []}, "explanation": "- `MCInstrument.MarginPercentage` 当前保证金比例\n- `MarginChangeDate` 变动日期", "question_en": "List all instruments with margin ratio changes effective today.", "rating": 7, "execution_result": null, "result_note": "当前查询无保证金比例变动记录", "tags": ["margin", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q20", "question_zh": "哪些公司行动的选择指令需在今日结束前提交?", "sql": "-- 查询今日截止的公司行动选择 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.ElectionPeriodTo AS Deadline,\n e.ElectionOptionFlag,\n e.Remark AS Description\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.ElectionPeriodTo = '2026-04-02'\n AND e.ElectionOptionFlag = 'Y'\n AND e.State = 'A';", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `ElectionPeriodTo` 选择截止日期\n- `ElectionOptionFlag = 'Y'` 需要选择", "question_en": "Which corporate action elections are due by end of day?", "rating": 8, "execution_result": null, "result_note": "当前查询无今日截止的选择", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q21", "question_zh": "截至昨日的客户借方余额应计利息是多少?", "sql": "-- 查询客户借方余额应计利息 (截至2026-04-01)\nSELECT \n SUM(AccruedDebitInterest) AS TotalDebitInterestAccrued,\n SUM(AccruedCreditInterest) AS TotalCreditInterestAccrued,\n SUM(AccruedDebitInterest) - SUM(AccruedCreditInterest) AS NetDebitInterest,\n COUNT(DISTINCT AccountID) AS AccountCount\nFROM BCAccountCash\nWHERE AccruedDebitInterest > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `AccruedDebitInterest` 借款应计利息\n- `AccruedCreditInterest` 存款应计利息", "question_en": "What is the interest accrued on client debit balances as of yesterday?", "rating": 8, "execution_result": null, "result_note": "| TotalDebitInterestAccrued | TotalCreditInterestAccrued | NetDebitInterest | AccountCount |\n|---------------------------|---------------------------|-----------------|-------------|\n| 2,022.70 | 464.15 | 1,558.55 | 55 |", "tags": ["filter", "account", "interest", "cash", "aggregation"], "difficulty": "hard"}
{"qid": "Q22", "question_zh": "列出今日所有公司账户与客户账户之间的现金划转。", "sql": "-- 查询公司账户与客户账户现金划转 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n a.AccountType,\n c.CurrencyID,\n c.TodayIn AS CashInflow,\n c.TodayOut AS CashOutflow,\n c.Settled AS CurrentBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE (c.TodayIn > 0 OR c.TodayOut > 0)\nORDER BY c.TodayIn + c.TodayOut DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- 公司账户与客户账户通过 `AccountType` 区分\n- `TodayIn/TodayOut` 记录现金流动", "question_en": "List all cash movements between house and client accounts today.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q23", "question_zh": "列出所有逾期未付保证金利息的账户。", "sql": "-- 查询逾期保证金利息账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.LoanInterestMarginOverdue AS MarginOverdueInterest,\n c.LoanInterestMarginBOverdue AS MarginBOverdueInterest,\n c.LoanInterestOverdue AS GeneralOverdueInterest\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.LoanInterestMarginOverdue > 0 \n OR c.LoanInterestMarginBOverdue > 0\n OR c.LoanInterestOverdue > 0\nORDER BY (c.LoanInterestMarginOverdue + c.LoanInterestMarginBOverdue + c.LoanInterestOverdue) DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `LoanInterestMarginOverdue` 保证金账户逾期利息\n- `LoanInterestMarginBOverdue` B类保证金逾期利息", "question_en": "Show all accounts with overdue margin interest payments.", "rating": 8, "execution_result": null, "result_note": "当前查询无逾期利息记录", "tags": ["join", "ordering", "margin", "filter", "account", "interest"], "difficulty": "hard"}
{"qid": "Q24", "question_zh": "有多少客户报表已生成成功但尚未发送?", "sql": "-- 查询已生成但未发送的报表\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n a.LastDailyStatementDate,\n a.LastMonthlyStatementDate,\n a.LastStatementGenerateTime,\n a.LastStatementSendTime,\n CASE \n WHEN a.LastStatementGenerateTime > a.LastStatementSendTime THEN '未发送'\n ELSE '已发送'\n END AS DeliveryStatus\nFROM MCAccount a\nWHERE a.LastStatementGenerateTime IS NOT NULL\n AND (a.LastStatementSendTime IS NULL \n OR a.LastStatementGenerateTime > a.LastStatementSendTime)\nORDER BY a.LastStatementGenerateTime DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `LastStatementGenerateTime` 报表生成时间\n- `LastStatementSendTime` 报表发送时间", "question_en": "How many client statements were successfully generated but not yet delivered?", "rating": 7, "execution_result": null, "result_note": "当前查询无未发送报表", "tags": ["ordering", "account", "filter", "statement"], "difficulty": "easy"}
{"qid": "Q25", "question_zh": "列出所有待批准的股票转移请求。", "sql": "-- 查询待批准的股票转移\nSELECT \n AccountID,\n InstrumentID,\n MovementType,\n MovementQuantity,\n FromAccountID,\n ToAccountID,\n RequestDate,\n ApprovalStatus,\n RequestedBy\nFROM BCAccountInstrumentMovement\nWHERE ApprovalStatus = 'P'\nORDER BY RequestDate DESC;", "schema_info": {"tables": {"BCAccountInstrumentMovement": {"alias": "BCAccountInstrumentMovement", "columns": []}}, "joins": []}, "explanation": "- 股票转移请求存储在专用表中\n- `ApprovalStatus = 'P'` 待批准状态", "question_en": "Show all pending stock movement requests that require approval.", "rating": 6, "execution_result": null, "result_note": "当前查询无待批准请求", "tags": ["filter", "ordering"], "difficulty": "easy"}
{"qid": "Q26", "question_zh": "本月各交易所的结算费用明细如何?", "sql": "-- 按交易所统计结算费用 (2026年4月)\n-- 说明:BCAccountInstrument 表中 TotalBoughtFee/TotalSoldFee 是持仓级别的交易费用字段\n-- LastTransactionDate 表示该持仓最后交易日期\n-- 查询逻辑:筛选最后交易日期在本月内的持仓记录,按交易所汇总交易费用\nSELECT \n bi.MarketID,\n m.MarketName,\n SUM(bi.TotalBoughtFee) AS TotalBuyFee,\n SUM(bi.TotalSoldFee) AS TotalSellFee,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalSettlementFee,\n COUNT(DISTINCT bi.AccountID) AS TradingAccountCount\nFROM BCAccountInstrument bi\nINNER JOIN MCMarket m ON bi.MarketID = m.MarketID\nWHERE bi.LastTransactionDate >= '2026-04-01' AND bi.LastTransactionDate < '2026-05-01'\nGROUP BY bi.MarketID, m.MarketName\nORDER BY TotalSettlementFee DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCMarket": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.MarketID = m.MarketID"}]}, "explanation": "- `BCAccountInstrument` 存储持仓级别信息,包含各持仓的交易费用累计\n- `MCMarket` 存储市场信息,提供市场名称\n- `LastTransactionDate` 用于过滤本月有交易的持仓记录\n- 按市场分组汇总结算费用", "question_en": "What is the breakdown of settlement fees by exchange for this month?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "trade", "aggregation", "date_range"], "difficulty": "hard"}
{"qid": "Q27", "question_zh": "列出所有超过3天的暂记账户分录。", "sql": "-- 查询超过3天的暂记账户分录 (2026-04-02)\n-- 说明:TCAccountCashMovement 是现金流水表\n-- NeedHoldFlag='Y' 表示暂记分录\n-- Amount - ReleasedAmount 表示未释放金额(暂记余额)\n-- 筛选未释放且超过3天的暂记分录\nSELECT \n cm.AccountID,\n cm.MovementID,\n cm.ValueDate,\n cm.CurrencyID,\n cm.Amount - ISNULL(cm.ReleasedAmount, 0) AS PendingBalance,\n cm.Remark,\n DATEDIFF(DAY, cm.ValueDate, '2026-04-02') AS DaysOutstanding\nFROM TCAccountCashMovement cm\nWHERE cm.NeedHoldFlag = 'Y'\n AND cm.Amount - ISNULL(cm.ReleasedAmount, 0) != 0\n AND DATEDIFF(DAY, cm.ValueDate, '2026-04-02') > 3\nORDER BY DaysOutstanding DESC, PendingBalance DESC;", "schema_info": {"tables": {"TCAccountCashMovement": {"alias": "cm", "columns": []}}, "joins": []}, "explanation": "- `TCAccountCashMovement` 存储现金流水记录\n- `NeedHoldFlag = 'Y'` 标识暂记(待确认)分录\n- `Amount - ReleasedAmount` 计算未释放的暂记余额\n- `DATEDIFF` 计算距今天数\n- `DATEDIFF > 3` 筛选超过3天的记录", "question_en": "List all suspense account entries older than 3 days.", "rating": 9, "execution_result": null, "result_note": "**查询结果:0条记录**\n\n当前没有超过3天未释放的暂记账户分录。所有暂记分录的 ReleasedAmount = Amount,已全部释放。", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q28", "question_zh": "哪些客户已请求更改结算货币?", "sql": "-- 查询请求更改结算货币的客户\n-- 说明:经查 MCAccountCurrency 表无 CurrencyChangeStatus/RequestedCurrencyID 等字段\n-- 数据库中没有专门的货币变更请求表\n-- 此查询基于账户货币历史时间表(HCAccountCurrencyTimetable)展示货币生效安排\nSELECT \n act.AccountID,\n mca.Name AS AccountName,\n act.CurrencyID AS Currency,\n act.EffectiveDateFrom,\n act.EffectiveDateTo,\n act.AccountTypeID\nFROM HCAccountCurrencyTimetable act\nINNER JOIN MCAccount mca ON act.AccountID = mca.AccountID\nWHERE act.EffectiveDateTo IS NULL\nORDER BY act.EffectiveDateFrom DESC;", "schema_info": {"tables": {"HCAccountCurrencyTimetable": {"alias": "act", "columns": []}, "MCAccount": {"alias": "mca", "columns": []}}, "joins": [{"type": "INNER", "on": "act.AccountID = mca.AccountID"}]}, "explanation": "- `HCAccountCurrencyTimetable` 记录账户货币生效时间表\n- `EffectiveDateTo IS NULL` 表示当前生效的货币配置\n- 如需货币变更请求功能,建议在系统中扩展相关表结构", "question_en": "Which clients have requested a change in settlement currency?", "rating": 4, "execution_result": null, "result_note": "**说明:** 数据库中没有专门的货币变更请求表。`MCAccountCurrency` 表仅记录账户当前货币配置,无变更请求字段。", "tags": ["join", "account", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q29", "question_zh": "列出后台系统中所有活跃用户账户及其最后登录日期。", "sql": "-- 查询活跃用户及其登录情况\nSELECT \n u.UserID,\n u.Name AS UserName,\n u.Status,\n u.LogonEnableFlag,\n u.LastLogonTime,\n u.BranchID,\n CASE u.CompanyAEFlag WHEN 'Y' THEN '公司经纪' ELSE '个人' END AS AEType,\n CASE \n WHEN u.LastLogonTime >= DATEADD(DAY, -7, GETDATE()) THEN '近7天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -30, GETDATE()) THEN '近30天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -90, GETDATE()) THEN '近90天活跃'\n ELSE '长期未登录'\n END AS ActivityStatus\nFROM MCUser u\nWHERE u.State = 'A'\n AND u.LogonEnableFlag = 'Y'\nORDER BY u.LastLogonTime DESC;", "schema_info": {"tables": {"MCUser": {"alias": "u", "columns": []}}, "joins": []}, "explanation": "- `MCUser` 存储用户信息\n- `LastLogonTime` 最后登录时间", "question_en": "List all active user accounts in the back office system with last login date.", "rating": 9, "execution_result": null, "result_note": "| UserID | UserName | Status | LogonEnableFlag | LastLogonTime | ActivityStatus |\n|--------|----------|--------|-----------------|---------------|----------------|\n| SUPPORT | SUPPORT | N | Y | 2026-04-08 | 近7天活跃 |\n| ROSANNA | ROSANNA | N | Y | 2025-10-21 | 长期未登录 |\n| SING | WONG LO SING | N | Y | 2025-10-21 | 长期未登录 |\n| LEONNG | LEON NG | N | Y | 2025-10-21 | 长期未登录 |", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q33", "question_zh": "今日是否有追缴保证金通知?", "sql": "-- 查询今日追缴保证金记录 (固定日期: 2026-04-02)\nSELECT \n m.AccountID,\n a.Name AS AccountName,\n m.CallForDeposit,\n m.CallForDepositDate,\n m.CallForDepositDays\nFROM HCAccountMarginCallForDeposit m\nINNER JOIN MCAccount a ON m.AccountID = a.AccountID\nWHERE m.CallForDepositDate = '2026-04-02';", "schema_info": {"tables": {"HCAccountMarginCallForDeposit": {"alias": "m", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "m.AccountID = a.AccountID"}]}, "explanation": "- `HCAccountMarginCallForDeposit` 记录追缴保证金信息\n- `CallForDeposit` 追缴金额", "question_en": "Have there been any margin calls today?", "rating": 9, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "margin", "filter"], "difficulty": "easy"}
{"qid": "Q34", "question_zh": "保证金账户前20大持仓(按市值)是多少?", "sql": "-- 保证金账户按市值排序的前20持仓\nSELECT TOP 20\n a.AccountID,\n a.Name AS AccountName,\n a.MarketValue,\n a.MarginDebitRatio AS MarginDebitBalanceRatio,\n a.MarginPosition,\n a.CallForDeposit,\n a.MarginFacilityFlag\nFROM MCAccount a\nWHERE a.MarginFacilityFlag = 'Y'\n AND a.State = 'A'\n AND a.MarketValue > 0\nORDER BY a.MarketValue DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 表包含所有账户信息\n- `MarginFacilityFlag = 'Y'` 筛选保证金账户", "question_en": "What are the top 20 holdings (based on market value) for margin accounts?", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginPosition |\n|-----------|-------------|------------|----------------|\n| M050009 | NG SUN SHU*** | 57,420,000 | 35,515,021.58 |\n| M050013 | NG CHUNG WAI*** | 19,504,520 | 10,918,958.78 |\n| M050193 | WONG KING YIU*** ^ | 11,682,920 | 3,340,099.05 |\n| P020160 | LAW SHIU MING DENNIS | 7,520,370 | 0 |\n| P030078 | MAK SUI BING | 7,120,309.94 | 0 |\n| P051101 | CHUNG CHUNG YEE | 7,117,808.04 | 0 |\n| M050170 | FUNG LAI FONG ANNA | 7,009,227.25 | 4,136,857 |\n| P220005 | LAI KAM SUI # | 5,837,102.10 | 97.97 |\n| P280628 | CHAN KWOK MO # | 5,761,997.48 | 62,508.23 |\n| P280455 | LEUNG KA CHI # | 5,487,971.20 | -64,981.22 |\n\n(共20条记录,以上展示前10条)", "tags": ["ordering", "holding", "margin", "filter", "limit", "account"], "difficulty": "hard"}
{"qid": "Q35", "question_zh": "列出本月按客户主任分组的佣金总额,以及相应的成交金额和返佣金额。", "sql": "-- 按经纪商/客户主任分组的佣金统计\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee) AS TotalBuyCommission,\n SUM(bi.TotalSoldFee) AS TotalSellCommission,\n SUM(bi.TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(bi.TotalSoldConsideration) AS TotalSellConsideration,\n SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE a.State = 'A'\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCAccount.AEID` 关联经纪商/客户主任\n- `BCAccountInstrument` 包含交易费用数据", "question_en": "List the total commission received this month by AE, along with corresponding consideration and rebate amounts.", "rating": 8, "execution_result": null, "result_note": "| AEID | AEName | AccountCount | TotalBuyCommission | TotalSellCommission | TotalCommission |\n|------|--------|-------------|-------------------|--------------------|----------------|\n| C01 | CHAN YUET HUNG | 628 | 183,244.64 | 187,220.59 | 370,465.23 |\n| C28 | CHAN SHU SHAN | 405 | 179,275.89 | 176,760.39 | 356,036.28 |\n| C05 | CENTRAL | 517 | 97,368.51 | 102,819.88 | 200,188.39 |\n| C33 | LEON NG | 13 | 71,541.06 | 72,620.60 | 144,161.66 |\n| C07 | CHAN WING PAI | 75 | 73,255.68 | 69,115.58 | 142,371.26 |\n| C10 | TOKWAWAN / KOWLOON CITY | 369 | 51,059.78 | 57,288.86 | 108,348.64 |\n| C08 | WONG HON KONG | 380 | 47,505.15 | 46,300.39 | 93,805.54 |\n| C36 | Name Of C36 | 146 | 40,945.66 | 35,682.86 | 76,628.52 |\n| C66 | CHEUNG YUK LING IVA | 17 | 24,458.82 | 22,723.18 | 47,182.00 |\n| C19 | WONG LO SING | 60 | 13,337.69 | 13,912.30 | 27,249.99 |\n\n(共15个AE有佣金记录,以上展示前10条)\n\n**注:** 当前SQL无日期条件,统计所有历史累计佣金。如需\"本月\"佣金,需添加 `LastTransactionDate >= '2026-04-01'` 条件。", "tags": ["join", "ordering", "filter", "account", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q36", "question_zh": "各市场(如港股T+1和T+2、美股T+1)的待结算金额是多少?", "sql": "-- 按市场统计待结算金额\nSELECT \n MarketID,\n SUM(DueBuy + DueSell) AS TotalPendingQty,\n SUM(NextDayDueBuy + NextDayDueSell) AS T2TotalPendingQty\nFROM BCAccountInstrument\nWHERE DueBuy > 0 OR DueSell > 0 OR NextDayDueBuy > 0 OR NextDayDueSell > 0\nGROUP BY MarketID;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 记录各市场的待交收数量\n- `DueBuy/DueSell` 对应T+1交收", "question_en": "What is the pending settlement amount for each market (e.g., HK T+1 & T+2, US T+1)?", "rating": 7, "execution_result": null, "result_note": "| MarketID | TotalPendingQty | T2TotalPendingQty |\n|----------|----------------|------------------|\n| HKEX | 0 | 0 |\n| SETW | 0 | 0 |", "tags": ["filter", "aggregation"], "difficulty": "medium"}
{"qid": "Q37", "question_zh": "是否有正在进行的IPO事件,其认购状态如何?", "sql": "-- 查询进行中的IPO (2026年4月)\nSELECT \n i.InstrumentID,\n i.MarketID,\n i.Name AS InstrumentName,\n i.State AS InstrumentStatus,\n ip.Quantity AS SubscriptionLot,\n ip.SubscriptionAmount,\n ip.CreatedOn AS SubscriptionDate\nFROM MCInstrument i\nINNER JOIN MCInstrumentIPODetail ip ON i.InstrumentID = ip.InstrumentID\nWHERE YEAR(ip.CreatedOn) = 2026\n AND MONTH(ip.CreatedOn) = 4\nORDER BY ip.CreatedOn DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "i", "columns": []}, "MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": [{"type": "INNER", "on": "i.InstrumentID = ip.InstrumentID"}]}, "explanation": "- `MCInstrument` 表记录证券信息\n- `MCInstrumentIPODetail` 记录IPO认购详情", "question_en": "Are there any IPO events currently in progress, and what is their subscription status?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "filter", "ipo", "ordering"], "difficulty": "easy"}
{"qid": "Q38", "question_zh": "本月IPO事件的总佣金、手续费和保证金利息是多少?", "sql": "-- IPO相关费用汇总 (2026年4月)\nSELECT \n 'IPO Commission' AS FeeType,\n SUM(ip.SubscriptionAmount * 0.001) AS EstimatedFee\nFROM MCInstrumentIPODetail ip\nWHERE YEAR(ip.CreatedOn) = 2026\n AND MONTH(ip.CreatedOn) = 4;", "schema_info": {"tables": {"MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": []}, "explanation": "- IPO相关费用分散在多个表中\n- 需要关联 `BCAccountInstrument` 获取IPO交易费用", "question_en": "What are the total commission, handling fees, and margin interest for IPO events this month?", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["margin", "aggregation", "filter", "interest"], "difficulty": "easy"}
{"qid": "Q39", "question_zh": "列出今日需要执行的公司行动(如权益分派)。", "sql": "-- 查询今日生效的公司行动 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.MarketID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.BalanceDate,\n e.BalanceExDate,\n e.Remark,\n e.State\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.State = 'A'\n AND (\n e.BalanceDate = '2026-04-02'\n OR e.BalanceExDate = '2026-04-02'\n OR e.AutoHoldDate = '2026-04-02'\n OR e.AutoDeductDate = '2026-04-02'\n );", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录所有权益分派信息\n- `BalanceDate` 权益登记日期", "question_en": "List corporate actions (e.g., entitlements) that need to be performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q40", "question_zh": "列出今日执行的所有股票转移/移动。", "sql": "-- 今日股票转入/转出 (固定日期: 2026-04-02)\nSELECT \n AccountID,\n MarketID,\n InstrumentID,\n TodayIn AS QuantityIn,\n TodayOut AS QuantityOut,\n HoldForDeposit AS PendingDeposit,\n HoldForWithdrawal AS PendingWithdrawal\nFROM BCAccountInstrument\nWHERE TodayIn > 0 OR TodayOut > 0;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 记录股票持仓变动\n- `TodayIn` 今日转入数量", "question_en": "List all stock movements performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["filter"], "difficulty": "easy"}
{"qid": "Q41", "question_zh": "列出今日执行的所有现金划转。", "sql": "-- 今日现金变动汇总 (固定日期: 2026-04-02)\nSELECT \n b.AccountID,\n a.Name AS AccountName,\n b.TodayIn AS CashIn,\n b.TodayOut AS CashOut,\n b.BankAvailableBalance\nFROM BCAccountCash b\nINNER JOIN MCAccount a ON b.AccountID = a.AccountID\nWHERE b.TodayIn > 0 OR b.TodayOut > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "b", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "b.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash` 记录账户现金变动\n- `TodayIn` 今日现金流入", "question_en": "List all cash movements performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "filter", "cash"], "difficulty": "easy"}
{"qid": "Q42", "question_zh": "列出后台系统中的活跃用户。", "sql": "-- 查询后台系统活跃用户\nSELECT \n u.UserID,\n u.Name AS UserName,\n u.Status,\n u.LogonEnableFlag,\n u.LastLogonTime,\n u.BranchID,\n u.DepartmentID,\n CASE u.CompanyAEFlag WHEN 'Y' THEN '公司经纪' ELSE '个人' END AS AEType\nFROM MCUser u\nWHERE u.State = 'A'\n AND u.LogonEnableFlag = 'Y'\nORDER BY u.LastLogonTime DESC;", "schema_info": {"tables": {"MCUser": {"alias": "u", "columns": []}}, "joins": []}, "explanation": "- `MCUser` 存储系统用户信息\n- `State = 'A'` 用户状态正常", "question_en": "List active users in the back office.", "rating": 9, "execution_result": null, "result_note": "| UserID | UserName | Status | LogonEnableFlag | LastLogonTime | AEType |\n|--------|----------|--------|-----------------|---------------|--------|\n| SUPPORT | SUPPORT | N | Y | 2026-04-03 18:53:04 | 个人 |\n| ROSANNA | ROSANNA | N | Y | 2025-10-21 16:47:11 | 个人 |", "tags": ["filter", "ordering"], "difficulty": "easy"}
{"qid": "Q43", "question_zh": "列出持仓为负数(透支)的账户。", "sql": "-- 查询透支持仓账户\nSELECT \n AccountID,\n Name AS AccountName,\n MarketValue,\n AssetBalance,\n LiabilityBalance,\n MarginPosition,\n MarginFacilityFlag\nFROM MCAccount\nWHERE MarketValue < 0\n AND State = 'A'\nORDER BY MarketValue ASC;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MarketValue < 0` 筛选持仓为负的账户\n- 持仓为负通常表示账户存在透支或结算问题", "question_en": "List accounts with overdrawn positions.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginFacilityFlag |\n|-----------|-------------|-------------|-------------------|\n| P030012 | LAI YEE TAK HELEN | -112,196.60 | N |\n| P350022 | CHAN YAU KING*** | -92,950.00 | N |\n| P011212 | NG SIU PING | -12,352.00 | N |", "tags": ["account", "holding", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q45", "question_zh": "不同经纪商(如非中央结算系统持仓)的客户总持仓是多少?", "sql": "-- 按托管位置统计持仓(非CCASS)\nSELECT \n loc.LocationID,\n loc.Name AS LocationName,\n COUNT(DISTINCT bi.AccountID) AS AccountCount,\n SUM(bi.Settled) AS TotalQuantity,\n SUM(bi.CostAmount) AS TotalCostAmount\nFROM BCAccountLocationInstrument bi\nINNER JOIN MCLocation loc ON bi.LocationID = loc.LocationID\nWHERE loc.CCASSFlag = 'N'\nGROUP BY loc.LocationID, loc.Name\nORDER BY TotalQuantity DESC;", "schema_info": {"tables": {"BCAccountLocationInstrument": {"alias": "bi", "columns": []}, "MCLocation": {"alias": "loc", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.LocationID = loc.LocationID"}]}, "explanation": "- `BCAccountLocationInstrument` 记录按托管位置分类的持仓\n- `MCLocation` 存储托管位置信息", "question_en": "What is the total client holding at different broker firms (e.g., non-CCASS locations)?", "rating": 7, "execution_result": null, "result_note": "当前查询需要验证 Location 表关联", "tags": ["join", "ordering", "holding", "broker", "filter", "account", "aggregation"], "difficulty": "hard"}
{"qid": "Q46", "question_zh": "支付给其他经纪商的佣金是多少?", "sql": "-- 查询支付给其他经纪商的佣金\nSELECT \n b.BrokerID,\n b.Name AS BrokerName,\n SUM(bc.Commission) AS TotalCommission,\n SUM(bc.Consideration) AS TotalConsideration\nFROM MCBroker b\nINNER JOIN BCBrokerCash bc ON b.BrokerID = bc.BrokerID\nWHERE bc.Commission > 0\nGROUP BY b.BrokerID, b.Name\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCBroker": {"alias": "b", "columns": []}, "BCBrokerCash": {"alias": "bc", "columns": []}}, "joins": [{"type": "INNER", "on": "b.BrokerID = bc.BrokerID"}]}, "explanation": "- `MCBroker` 存储经纪商信息\n- `BCBrokerCash` 可能包含经纪商现金和佣金数据", "question_en": "How much commission has been paid to other brokers?", "rating": 6, "execution_result": null, "result_note": "当前查询需要验证经纪商佣金表关联", "tags": ["join", "ordering", "broker", "filter", "aggregation"], "difficulty": "hard"}
{"qid": "Q47", "question_zh": "今日/指定日期发放了多少份日结单或月结单?", "sql": "-- 查询报表发放统计 (2026-04-02)\nSELECT \n 'Daily Statement' AS StatementType,\n COUNT(*) AS StatementCount\nFROM MCAccount\nWHERE LastDailyStatementDate = '2026-04-02'\nUNION ALL\nSELECT \n 'Monthly Statement' AS StatementType,\n COUNT(*) AS StatementCount\nFROM MCAccount\nWHERE LastMonthlyStatementDate = '2026-04-02';", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 记录账户报表发送日期\n- `LastDailyStatementDate` 最近日结单发送日期", "question_en": "How many daily or monthly statements were issued today / on a specific date?", "rating": 9, "execution_result": null, "result_note": "", "tags": ["union", "filter", "aggregation"], "difficulty": "hard"}
{"qid": "Q48", "question_zh": "列出所有支持保证金的证券及其相应的保证金比例。", "sql": "-- 查询支持保证金的证券\nSELECT \n InstrumentID,\n Name AS InstrumentName,\n MarginPercentage AS MarginRatio,\n CASE \n WHEN MarginPercentage >= 0.7 THEN '高'\n WHEN MarginPercentage >= 0.5 THEN '中'\n WHEN MarginPercentage > 0 THEN '低'\n ELSE 'N/A'\n END AS RiskLevel,\n MarginLimitPerInstrument,\n CollateralRatio\nFROM MCInstrument\nWHERE MarginPercentage IS NOT NULL\n AND MarginPercentage > 0\n AND State = 'A'\nORDER BY MarginPercentage DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "MCInstrument", "columns": []}}, "joins": []}, "explanation": "- `MCInstrument` 存储证券信息\n- `MarginPercentage` 保证金比例", "question_en": "List all instruments that support margin and their corresponding margin ratios.", "rating": 9, "execution_result": null, "result_note": "| InstrumentID | InstrumentName | MarginRatio | RiskLevel |\n|-------------|----------------|-------------|-----------|\n| 00001 | CKH HOLDINGS(S) | 0.70 | 高 |\n| 00002 | CLP HOLDINGS(S) | 0.70 | 高 |\n| 00003 | HK & CHINA GAS(S) | 0.70 | 高 |\n\n(共767条记录)", "tags": ["margin", "limit", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q49", "question_zh": "本月、本季度和今年分别开了多少账户?", "sql": "-- 开户统计 (2026年4月)\nSELECT \n COUNT(CASE WHEN MONTH(OpenDate) = 4 AND YEAR(OpenDate) = 2026 THEN 1 END) AS April2026,\n COUNT(CASE WHEN DATEPART(QUARTER, OpenDate) = 2 AND YEAR(OpenDate) = 2026 THEN 1 END) AS Q2_2026,\n COUNT(CASE WHEN YEAR(OpenDate) = 2026 THEN 1 END) AS Year2026,\n COUNT(*) AS TotalAccounts,\n MIN(OpenDate) AS EarliestOpenDate,\n MAX(OpenDate) AS LatestOpenDate\nFROM MCAccount\nWHERE OpenDate IS NOT NULL;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.OpenDate` 账户开户日期\n- 按月、季度、年分别统计新开户数量", "question_en": "How many accounts were opened this month, this quarter, and this year?", "rating": 9, "execution_result": null, "result_note": "| April2026 | Q2_2026 | Year2026 | TotalAccounts | EarliestOpenDate | LatestOpenDate |\n|-----------|---------|----------|---------------|------------------|----------------|\n| 0 | 0 | 0 | 1,951 | 1993-03-05 | 2025-10-16 |", "tags": ["account", "limit", "filter", "aggregation"], "difficulty": "easy"}
{"qid": "Q50", "question_zh": "", "sql": "SELECT TOP\n\t15 c.ContractID,\n\tc.TradeDate,\n\tLTRIM( RTRIM( c.AccountID ) ) AS AccountID,\n\tLTRIM( RTRIM( c.MarketID ) ) AS MarketID,\n\tc.InstrumentID,\n\tc.BuySell,\n\tc.Quantity,\n\tc.Consideration,\n\tLTRIM( RTRIM( c.CurrencyID ) ) AS CurrencyID \nFROM\n\tdbo.TSBAccountContract c\n\tINNER JOIN dbo.MCAccount a ON c.AccountID = a.AccountID \nWHERE\n\tCAST ( c.TradeDate AS DATE ) = '2026-04-02' \n\tAND LTRIM( RTRIM( a.HouseAccountFlag ) ) = 'N' \nORDER BY\n\tc.ContractID;", "schema_info": {"tables": {"TSBAccountContract": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "", "question_en": "列出今天所有客戶的交易記錄", "rating": null, "execution_result": null, "result_note": "| ContractID | TradeDate | AccountID | MarketID | InstrumentID | BuySell | Quantity | Consideration | CurrencyID |\n| :--------- | :--------- | :-------- | :------- | :----------- | :------ | :------- | :------------ | :--------- |\n| B02403846 | 2026-04-02 | P011206 | HKEX | 01810 | B | 600 | 18360 | HKD |\n| B02403847 | 2026-04-02 | P011202 | HKEX | 01810 | B | 200 | 6120 | HKD |\n\n\n\n\n\n---\n\n## 附录:关键表说明\n\n| 表名 | 说明 | 关键字段 |\n|------|------|---------|\n| MCAccount | 账户主表 | AccountID, Name, MarketValue, MarginFacilityFlag |\n| MCUser | 用户表 | UserID, Name, Status, LogonEnableFlag |\n| BCAccountInstrument | 账户持仓 | AccountID, MarketID, Settled, DueBuy, DueSell |\n| BCAccountCash | 账户现金 | AccountID, TodayIn, TodayOut, AccruedInterest |\n| HCAccountMarginCallForDeposit | 追缴保证金 | AccountID, CallForDeposit, CallForDepositDate |\n| MCInstrument | 证券表 | InstrumentID, Name, MarginPercentage |\n| MCInstrumentIPODetail | IPO详情 | InstrumentID, Quantity, SubscriptionAmount |\n| MSBEntitlement | 权益分派 | EntitlementID, BalanceDate, BalanceExDate |\n| MCBroker | 经纪商 | BrokerID, Name |\n| MCLocation | 托管位置 | LocationID, Name, CCASSFlag |\n| HCExchangeRate | 汇率 | ExchangeRateID, ValueDate |\n| HCAccountCashRecord | 现金记录 | AccountID, ValueDate, LedgerBalance |\n\n---\n\n**文档结束**", "tags": ["join", "limit", "filter", "ordering"], "difficulty": "easy"}
+4
View File
@@ -0,0 +1,4 @@
{"qid": "Q32", "question_zh": "各市场客户不同资产(如股票、债券、基金、虚拟资产)的总持仓是多少?", "sql": "-- 按市场统计客户持仓\nSELECT \n b.MarketID,\n COUNT(DISTINCT b.AccountID) AS AccountCount,\n SUM(b.Settled) AS TotalQuantity,\n SUM(b.CostAmount) AS TotalCostAmount,\n SUM(b.TotalBoughtQuantity) AS TotalBoughtQty,\n SUM(b.TotalSoldQuantity) AS TotalSoldQty\nFROM BCAccountInstrument b\nGROUP BY b.MarketID\nORDER BY TotalCostAmount DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "b", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表记录账户在各市场的持仓\n- `MarketID` 区分不同市场", "question_en": "What is the total client holding of different assets (e.g., stocks, bonds, funds, virtual assets) by each market?", "rating": 8, "execution_result": null, "result_note": "| MarketID | AccountCount | TotalQuantity | TotalCostAmount | TotalBoughtQty | TotalSoldQty |\n|----------|-------------|---------------|-----------------|---------------|-------------|\n| HKEX | 2,102 | 717,471,548 | 87,813,213.45 | 1,015,923,906 | 298,452,798 |\n| SETW | 2 | 3,100 | 32,298.50 | 4,100 | 1,000 |", "tags": ["account", "holding", "ordering", "aggregation"], "difficulty": "medium"}
{"qid": "Q34", "question_zh": "保证金账户前20大持仓(按市值)是多少?", "sql": "-- 保证金账户按市值排序的前20持仓\nSELECT TOP 20\n a.AccountID,\n a.Name AS AccountName,\n a.MarketValue,\n a.MarginDebitRatio AS MarginDebitBalanceRatio,\n a.MarginPosition,\n a.CallForDeposit,\n a.MarginFacilityFlag\nFROM MCAccount a\nWHERE a.MarginFacilityFlag = 'Y'\n AND a.State = 'A'\n AND a.MarketValue > 0\nORDER BY a.MarketValue DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 表包含所有账户信息\n- `MarginFacilityFlag = 'Y'` 筛选保证金账户", "question_en": "What are the top 20 holdings (based on market value) for margin accounts?", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginPosition |\n|-----------|-------------|------------|----------------|\n| M050009 | NG SUN SHU*** | 57,420,000 | 35,515,021.58 |\n| M050013 | NG CHUNG WAI*** | 19,504,520 | 10,918,958.78 |\n| M050193 | WONG KING YIU*** ^ | 11,682,920 | 3,340,099.05 |\n| P020160 | LAW SHIU MING DENNIS | 7,520,370 | 0 |\n| P030078 | MAK SUI BING | 7,120,309.94 | 0 |\n| P051101 | CHUNG CHUNG YEE | 7,117,808.04 | 0 |\n| M050170 | FUNG LAI FONG ANNA | 7,009,227.25 | 4,136,857 |\n| P220005 | LAI KAM SUI # | 5,837,102.10 | 97.97 |\n| P280628 | CHAN KWOK MO # | 5,761,997.48 | 62,508.23 |\n| P280455 | LEUNG KA CHI # | 5,487,971.20 | -64,981.22 |\n\n(共20条记录,以上展示前10条)", "tags": ["ordering", "holding", "margin", "filter", "limit", "account"], "difficulty": "hard"}
{"qid": "Q43", "question_zh": "列出持仓为负数(透支)的账户。", "sql": "-- 查询透支持仓账户\nSELECT \n AccountID,\n Name AS AccountName,\n MarketValue,\n AssetBalance,\n LiabilityBalance,\n MarginPosition,\n MarginFacilityFlag\nFROM MCAccount\nWHERE MarketValue < 0\n AND State = 'A'\nORDER BY MarketValue ASC;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MarketValue < 0` 筛选持仓为负的账户\n- 持仓为负通常表示账户存在透支或结算问题", "question_en": "List accounts with overdrawn positions.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginFacilityFlag |\n|-----------|-------------|-------------|-------------------|\n| P030012 | LAI YEE TAK HELEN | -112,196.60 | N |\n| P350022 | CHAN YAU KING*** | -92,950.00 | N |\n| P011212 | NG SIU PING | -12,352.00 | N |", "tags": ["account", "holding", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q45", "question_zh": "不同经纪商(如非中央结算系统持仓)的客户总持仓是多少?", "sql": "-- 按托管位置统计持仓(非CCASS)\nSELECT \n loc.LocationID,\n loc.Name AS LocationName,\n COUNT(DISTINCT bi.AccountID) AS AccountCount,\n SUM(bi.Settled) AS TotalQuantity,\n SUM(bi.CostAmount) AS TotalCostAmount\nFROM BCAccountLocationInstrument bi\nINNER JOIN MCLocation loc ON bi.LocationID = loc.LocationID\nWHERE loc.CCASSFlag = 'N'\nGROUP BY loc.LocationID, loc.Name\nORDER BY TotalQuantity DESC;", "schema_info": {"tables": {"BCAccountLocationInstrument": {"alias": "bi", "columns": []}, "MCLocation": {"alias": "loc", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.LocationID = loc.LocationID"}]}, "explanation": "- `BCAccountLocationInstrument` 记录按托管位置分类的持仓\n- `MCLocation` 存储托管位置信息", "question_en": "What is the total client holding at different broker firms (e.g., non-CCASS locations)?", "rating": 7, "execution_result": null, "result_note": "当前查询需要验证 Location 表关联", "tags": ["join", "ordering", "holding", "broker", "filter", "account", "aggregation"], "difficulty": "hard"}
+4
View File
@@ -0,0 +1,4 @@
{"qid": "Q21", "question_zh": "截至昨日的客户借方余额应计利息是多少?", "sql": "-- 查询客户借方余额应计利息 (截至2026-04-01)\nSELECT \n SUM(AccruedDebitInterest) AS TotalDebitInterestAccrued,\n SUM(AccruedCreditInterest) AS TotalCreditInterestAccrued,\n SUM(AccruedDebitInterest) - SUM(AccruedCreditInterest) AS NetDebitInterest,\n COUNT(DISTINCT AccountID) AS AccountCount\nFROM BCAccountCash\nWHERE AccruedDebitInterest > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `AccruedDebitInterest` 借款应计利息\n- `AccruedCreditInterest` 存款应计利息", "question_en": "What is the interest accrued on client debit balances as of yesterday?", "rating": 8, "execution_result": null, "result_note": "| TotalDebitInterestAccrued | TotalCreditInterestAccrued | NetDebitInterest | AccountCount |\n|---------------------------|---------------------------|-----------------|-------------|\n| 2,022.70 | 464.15 | 1,558.55 | 55 |", "tags": ["filter", "account", "interest", "cash", "aggregation"], "difficulty": "hard"}
{"qid": "Q23", "question_zh": "列出所有逾期未付保证金利息的账户。", "sql": "-- 查询逾期保证金利息账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.LoanInterestMarginOverdue AS MarginOverdueInterest,\n c.LoanInterestMarginBOverdue AS MarginBOverdueInterest,\n c.LoanInterestOverdue AS GeneralOverdueInterest\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.LoanInterestMarginOverdue > 0 \n OR c.LoanInterestMarginBOverdue > 0\n OR c.LoanInterestOverdue > 0\nORDER BY (c.LoanInterestMarginOverdue + c.LoanInterestMarginBOverdue + c.LoanInterestOverdue) DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `LoanInterestMarginOverdue` 保证金账户逾期利息\n- `LoanInterestMarginBOverdue` B类保证金逾期利息", "question_en": "Show all accounts with overdue margin interest payments.", "rating": 8, "execution_result": null, "result_note": "当前查询无逾期利息记录", "tags": ["join", "ordering", "margin", "filter", "account", "interest"], "difficulty": "hard"}
{"qid": "Q38", "question_zh": "本月IPO事件的总佣金、手续费和保证金利息是多少?", "sql": "-- IPO相关费用汇总 (2026年4月)\nSELECT \n 'IPO Commission' AS FeeType,\n SUM(ip.SubscriptionAmount * 0.001) AS EstimatedFee\nFROM MCInstrumentIPODetail ip\nWHERE YEAR(ip.CreatedOn) = 2026\n AND MONTH(ip.CreatedOn) = 4;", "schema_info": {"tables": {"MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": []}, "explanation": "- IPO相关费用分散在多个表中\n- 需要关联 `BCAccountInstrument` 获取IPO交易费用", "question_en": "What are the total commission, handling fees, and margin interest for IPO events this month?", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["margin", "aggregation", "filter", "interest"], "difficulty": "easy"}
{"qid": "Q44", "question_zh": "本月收到/支付的利息金额是多少(如客户借款利息和存款利息)?", "sql": "-- 本月利息收支汇总 (2026年4月)\nSELECT \n SUM(AccruedCreditInterest) AS CreditInterest,\n SUM(AccruedDebitInterest) AS DebitInterest,\n SUM(AccruedCreditInterest) - SUM(AccruedDebitInterest) AS NetInterest\nFROM BCAccountCash;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `BCAccountCash` 记录账户现金和利息信息\n- `AccruedCreditInterest` 应计存款利息", "question_en": "What is the interest amount received/paid this month (e.g., client debit interest and credit interest)?", "rating": 7, "execution_result": null, "result_note": "| CreditInterest | DebitInterest | NetInterest |\n|----------------|---------------|-------------|\n| 464.15 | 2,022.70 | -1,558.55 |", "tags": ["account", "aggregation", "interest"], "difficulty": "easy"}
+1
View File
@@ -0,0 +1 @@
{"qid": "Q37", "question_zh": "是否有正在进行的IPO事件,其认购状态如何?", "sql": "-- 查询进行中的IPO (2026年4月)\nSELECT \n i.InstrumentID,\n i.MarketID,\n i.Name AS InstrumentName,\n i.State AS InstrumentStatus,\n ip.Quantity AS SubscriptionLot,\n ip.SubscriptionAmount,\n ip.CreatedOn AS SubscriptionDate\nFROM MCInstrument i\nINNER JOIN MCInstrumentIPODetail ip ON i.InstrumentID = ip.InstrumentID\nWHERE YEAR(ip.CreatedOn) = 2026\n AND MONTH(ip.CreatedOn) = 4\nORDER BY ip.CreatedOn DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "i", "columns": []}, "MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": [{"type": "INNER", "on": "i.InstrumentID = ip.InstrumentID"}]}, "explanation": "- `MCInstrument` 表记录证券信息\n- `MCInstrumentIPODetail` 记录IPO认购详情", "question_en": "Are there any IPO events currently in progress, and what is their subscription status?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "filter", "ipo", "ordering"], "difficulty": "easy"}
+26
View File
@@ -0,0 +1,26 @@
{"qid": "Q1", "question_zh": "按对手方列出截至[日期]的所有未结算交易。", "sql": "-- 按对手方统计截至 2026-04-02 的未结算交易\n-- 使用 TSBBrokerContract(经纪商合约表),按 BrokerID(对手方经纪商)分组\n-- SettleStatus='U' 表示未结算;CashSettleDate <= '2026-04-02' 筛选截至日\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n COUNT(*) AS UnsettledTradeCount,\n SUM(b.SettleQuantity) AS TotalUnsettledQty,\n SUM(b.SettleAmount) AS TotalUnsettledAmount,\n MIN(b.BuySell) + '~' + MAX(b.BuySell) AS BuySellRange,\n MIN(b.CashSettleDate) AS EarliestSettleDate,\n MAX(b.CashSettleDate) AS LatestSettleDate\nFROM TSBBrokerContract b\nLEFT JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.SettleStatus = 'U'\n AND b.CashSettleDate <= '2026-04-02'\nGROUP BY b.BrokerID, m.Name\nORDER BY TotalUnsettledAmount DESC;", "schema_info": {"tables": {"TSBBrokerContract": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "LEFT", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `TSBBrokerContract` 是经纪商/对手方合约表,记录与外部对手方的交易合约,`BrokerID` 即对手方标识\n- `SettleStatus = 'U'` 表示未结算;`CashSettleDate <= '2026-04-02'` 筛选截至日未结清的合约\n- 关联 `MCBroker` 获取对手方经纪商名称\n- 按 `BrokerID` 分组汇总未结算数量和金额", "question_en": "Show all unsettled trades as of [date] grouped by counterparty.", "rating": 9, "execution_result": null, "result_note": "| BrokerID | BrokerName | UnsettledTradeCount | TotalUnsettledQty | TotalUnsettledAmount | BuySellRange | EarliestSettleDate | LatestSettleDate |\n|----------|-----------|---------------------|-------------------|---------------------|--------------|---------------------|-------------------|\n| CCASS | CCASS | 622 | 40,459,253 | 44,173,571.06 | B~S | 2025-07-30 | 2026-04-02 |\n\n> **注**:CCASS(Hong Kong Securities Clearing Company Limited)是香港交易所的中央结算机构,作为交易所交易的核心对手方。622笔未结算合约均为 HKEX 市场。", "tags": ["join", "ordering", "broker", "filter", "trade", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q2", "question_zh": "列出今日所有客户账户之间的股票转移记录。", "sql": "-- 查询今日客户账户间股票转移(参考日期:2026-04-02)\n-- 使用 TSBAccountInstrumentMovement,MovementType='T' 表示账户间转移\n-- ValueDate 为转移生效日期,关联 MCInstrument 获取证券名称\nSELECT \n m.MovementID,\n m.AccountID AS FromAccountID,\n m.TransferToAccountID,\n m.InstrumentID,\n i.Name AS InstrumentSymbol,\n m.MovementType,\n m.Quantity AS TransferQuantity,\n m.ValueDate AS TransferDate\nFROM TSBAccountInstrumentMovement m\nLEFT JOIN MCInstrument i ON m.InstrumentID = i.InstrumentID\nWHERE m.MovementType = 'T'\n AND m.ValueDate = '2026-04-02'\nORDER BY m.ValueDate;", "schema_info": {"tables": {"TSBAccountInstrumentMovement": {"alias": "m", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "LEFT", "on": "m.InstrumentID = i.InstrumentID"}]}, "explanation": "- `TSBAccountInstrumentMovement` 是持仓变动流水表,记录所有证券变动事件\n- `MovementType = 'T'`(Transfer)特指**账户间股票转移**,对应 `TransferToAccountID` 记录目标账户\n- `ValueDate` 是转移生效日期,可按日期过滤\n- 关联 `MCInstrument` 获取证券代码/名称\n- 注意:`BCAccountInstrument` 的 `TodayIn/TodayOut` 是**实时快照**,不带历史日期维度,不能用于查历史转移", "question_en": "List all stock transfers between client accounts performed today.", "rating": 9, "execution_result": null, "result_note": "当前查询无结果(测试环境中 `TSBAccountInstrumentMovement` 的 `MovementType='T'` 最新记录为 2025-10-21,无 2026-04-02 的账户间转移数据)", "tags": ["join", "ordering", "filter", "account", "left_join"], "difficulty": "hard"}
{"qid": "Q4", "question_zh": "哪些券商尚有未履行的交收义务?", "sql": "-- 查询有未履行交收义务的经纪商(截至 2026-04-02)\n-- Settled < 0 表示经纪商欠我们的现金(未履行交收义务)\n-- 注意:BCBrokerCash.Settled 是经纪商在我们账户的已结算现金余额,负数=经纪商欠款\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n b.CurrencyID,\n b.Settled AS OwedToUsAmount,\n ABS(b.Settled) AS OutstandingAmount\nFROM BCBrokerCash b\nINNER JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.Settled < 0\nORDER BY ABS(b.Settled) DESC;", "schema_info": {"tables": {"BCBrokerCash": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `BCBrokerCash` 记录经纪商在我们账户的结算现金,`Settled < 0` = 经纪商欠我们(未履行交收义务)\n- 关联 `MCBroker` 获取经纪商名称\n- 按欠款金额降序排列,优先处理大额欠款", "question_en": "Which brokers have outstanding delivery obligations to us?", "rating": 8, "execution_result": null, "result_note": "| BrokerID | BrokerName | CurrencyID | OwedToUsAmount | OutstandingAmount |\n|----------|-----------|------------|-----------------|-------------------|\n| CCASS | CCASS | CNY | -52,680.00 | 52,680.00 |\n| CCASS | CCASS | USD | -90.00 | 90.00 |\n\n> 注:CCASS 欠我们的结算现金(CNY 52,680 + USD 90)。HKD 余额为正(+4,202,811.87)表示我们欠 CCASS,不属于\"未履行交收义务\"范畴。", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q7", "question_zh": "今日结算后现金余额为负的账户列表。", "sql": "-- 查询现金余额为负的账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.Settled AS CashBalance,\n c.UnderdueCheque,\n c.BankAvailableBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.Settled < 0\nORDER BY c.Settled ASC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash.Settled` 表示已结算现金余额\n- 负数表示账户透支\n- 关联 `MCAccount` 获取账户名称", "question_en": "List accounts with negative cash balance after today's settlement.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | CurrencyID | CashBalance |\n|-----------|------------|------------|-------------|\n| M050009 | NG SUN SHU*** | HKD | -4,678,978.42 |\n| P050667 | WONG YIM HUNG | HKD | -780,196.94 |\n| M050521 | LO CHUN YIP | HKD | -290,487.54 |\n\n(共55个账户现金余额为负)", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q8", "question_zh": "明天生效的公司行动涉及哪些证券?", "sql": "-- 查询明日生效的公司行动 (固定日期: 2026-04-03)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.BalanceDate AS EffectiveDate,\n e.BalanceExDate AS ExDate,\n e.Remark AS Description\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE (e.BalanceDate = '2026-04-03' OR e.BalanceExDate = '2026-04-03')\n AND e.State = 'A';", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录权益分派信息\n- `BalanceDate` 权益登记日期\n- `BalanceExDate` 除权日期", "question_en": "Which instruments have corporate actions effective tomorrow?", "rating": 8, "execution_result": null, "result_note": "当前查询无结果(2026-04-03无公司行动)", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q9", "question_zh": "今日预计收到哪些股息?", "sql": "-- 查询今日预计收到的股息 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceDate AS PaymentDate,\n e.BalanceType,\n e.Remark AS DividendDetails\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.BalanceDate = '2026-04-02'\n AND e.BalanceType = 'C'\n AND e.State = 'A'\nORDER BY i.Name;", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录所有权益分派\n- `BalanceType = 'C'` 表示现金股息\n- `BalanceDate` 股息支付日期", "question_en": "What dividends are expected to be received today?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q10", "question_zh": "列出所有进行中IPO的待缴申购金额。", "sql": "-- 查询进行中IPO的待缴金额\nSELECT \n ip.InstrumentID,\n i.Name AS InstrumentName,\n i.State AS InstrumentStatus,\n ip.SubscriptionAmount,\n ip.SubscriptionPrice,\n ip.Quantity AS SubscriptionLot,\n ip.CreatedOn AS SubscriptionDate,\n ip.State AS SubscriptionStatus\nFROM MCInstrumentIPODetail ip\nINNER JOIN MCInstrument i ON ip.InstrumentID = i.InstrumentID\nWHERE ip.State = 'A'\n AND i.State = 'A'\nORDER BY ip.CreatedOn DESC;", "schema_info": {"tables": {"MCInstrumentIPODetail": {"alias": "ip", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "ip.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MCInstrumentIPODetail` 记录IPO认购详情\n- `SubscriptionAmount` 申购金额\n- `State = 'A'` 表示进行中", "question_en": "Show all pending subscription amounts for ongoing IPOs.", "rating": 8, "execution_result": null, "result_note": "| InstrumentID | InstrumentName | SubscriptionAmount | SubscriptionPrice | Quantity |\n|--------------|----------------|-------------------|-------------------|----------|\n| 02259 | HKEX | 7,231.19 | 36.16 | 100 |\n| 02259 | HKEX | 14,462.40 | 36.16 | 200 |\n\n> 注:MCInstrumentIPODetail 共 586 条进行中 IPO 记录(State='A'),以上为示例行。", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q11", "question_zh": "哪些客户尚未缴纳IPO申购款?", "sql": "-- 查询未缴纳IPO申购款的账户\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.TotalBoughtQuantity AS SubscriptionLot,\n bi.TotalBoughtConsideration AS SubscriptionAmount\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nINNER JOIN MCInstrumentIPODetail ip ON bi.InstrumentID = ip.InstrumentID\nWHERE ip.State = 'A'\n AND bi.TotalBoughtConsideration > 0\n AND bi.TotalBoughtFee = 0\nORDER BY bi.TotalBoughtConsideration DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}, "MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}, {"type": "INNER", "on": "bi.InstrumentID = ip.InstrumentID"}]}, "explanation": "- 通过比对买卖数量和手续费判断是否缴款\n- `TotalBoughtConsideration > 0` 有认购\n- `TotalBoughtFee = 0` 未支付手续费", "question_en": "Which clients have not yet paid their IPO subscription money?", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "ordering"], "difficulty": "hard"}
{"qid": "Q13", "question_zh": "列出今日到期的所有股票借贷交易。", "sql": "-- 查询今日到期的股票借贷 (参考日期: 2026-04-02)\n-- MCMarket 表仅包含 HKEX/OSL/SETW,无独立借贷市场标识\n-- 股票借贷可能在持仓变动类型 HoldType 中标识,或在专门的 StockBorrowing 表中\n-- 此 SQL 按 DueBuy/DueSell 显示当前待交收证券,作为借贷合约的近似替代\nSELECT \n bi.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.DueBuy AS BorrowQuantity,\n bi.DueSell AS LoanQuantity,\n bi.DueBuy - bi.DueSell AS NetBorrow\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nWHERE bi.DueBuy > 0 OR bi.DueSell > 0;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}]}, "explanation": "- `DueBuy/DueSell` 表示待交收数量(借款买入/借出卖出),反映股票借贷待到期情况\n- `MCMarket` 表无 `MarketType='BORROW'` 标识,现有市场仅为 HKEX/OSL/SETW\n- 股票借贷详情可能存储在 `TSBAccountLoanContract` 或其他借贷专用表中,需业务确认", "question_en": "List all stock borrow/loan transactions due to settle today.", "rating": 5, "execution_result": null, "result_note": "当前查询无结果(BCAccountInstrument 中 DueBuy/DueSell 均为 0,无待交收证券)", "tags": ["join", "trade", "filter"], "difficulty": "medium"}
{"qid": "Q14", "question_zh": "列出已申请但尚未处理的客户提款请求。", "sql": "-- 查询待处理提款申请 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.TodayOut AS WithdrawalAmount,\n c.BankAvailableBalance AS AvailableBalance,\n c.State AS RecordStatus\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.TodayOut > 0\nORDER BY c.TodayOut DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `TodayOut` 今日计划支出\n- 待处理提款申请应体现在此字段", "question_en": "Show all client withdrawals requested but not yet processed.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q15", "question_zh": "本月应付给介绍经纪人的佣金返佣总额是多少?", "sql": "-- 查询本月应付返佣 (2026年4月)\n-- 注意:BCAccountInstrument 无 UpdatedAt 字段,用 LastTransactionDate 过滤本月有交易的账户\n-- 说明:TotalBoughtFee/TotalSoldFee 为历史累计字段,此处统计近期活跃账户的累计佣金供参考\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE YEAR(bi.LastTransactionDate) = 2026\n AND MONTH(bi.LastTransactionDate) = 4\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee + bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCRebateScheme` 可能存储返佣规则\n- 按AE汇总佣金", "question_en": "What is the total commission rebate payable to introducing brokers this month?", "rating": 6, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q16", "question_zh": "列出T+2交易缺少结算指令的账户。", "sql": "-- 查询T+2待交收但缺少指令的账户\n-- 注意:BCAccountInstrumentInstruction 表不存在,需改用 TSBSettlementInstruction\nSELECT \n bi.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.NextDayDueBuy AS T2DueBuy,\n bi.NextDayDueSell AS T2DueSell\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nWHERE (bi.NextDayDueBuy > 0 OR bi.NextDayDueSell > 0)\n AND NOT EXISTS (\n SELECT 1 FROM TSBSettlementInstruction si\n WHERE si.AccountOrBrokerID = bi.AccountID\n AND si.InstrumentID = bi.InstrumentID\n AND si.State IN ('P','A')\n );", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}, "TSBSettlementInstruction": {"alias": "si", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}]}, "explanation": "- `NextDayDueBuy/NextDayDueSell` T+2交收数量(次日到期)\n- `TSBSettlementInstruction` 是结算指令表,通过 `NOT EXISTS` 排除已有指令的记录\n- `BCAccountInstrumentInstruction` 表不存在,不能使用", "question_en": "Show accounts where settlement instruction is missing for T+2 trades.", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "trade"], "difficulty": "medium"}
{"qid": "Q18", "question_zh": "今日收到的未清算支票总额是多少?", "sql": "-- 查询未清算支票 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.UnderdueCheque AS OverdueCheque,\n c.NextDayDueCheque AS PendingCheque,\n c.UnderdueCheque + c.NextDayDueCheque AS TotalUncleared\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE (c.UnderdueCheque > 0 OR c.NextDayDueCheque > 0) -- 注意:BCAccountCash 无这两个字段,需确认实际表\nORDER BY TotalUncleared DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash` 无 `UnderdueCheque` / `NextDayDueCheque` 字段,需业务确认支票数据存储位置", "question_en": "What is the total amount of uncleared cheques received today?", "rating": 4, "execution_result": null, "result_note": "当前查询无未清算支票", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q20", "question_zh": "哪些公司行动的选择指令需在今日结束前提交?", "sql": "-- 查询今日截止的公司行动选择 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.ElectionPeriodTo AS Deadline,\n e.ElectionOptionFlag,\n e.Remark AS Description\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.ElectionPeriodTo = '2026-04-02'\n AND e.ElectionOptionFlag = 'Y'\n AND e.State = 'A';", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `ElectionPeriodTo` 选择截止日期\n- `ElectionOptionFlag = 'Y'` 需要选择", "question_en": "Which corporate action elections are due by end of day?", "rating": 8, "execution_result": null, "result_note": "当前查询无今日截止的选择", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q22", "question_zh": "列出今日所有公司账户与客户账户之间的现金划转。", "sql": "-- 查询公司账户与客户账户现金划转 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n a.AccountType,\n c.CurrencyID,\n c.TodayIn AS CashInflow,\n c.TodayOut AS CashOutflow,\n c.Settled AS CurrentBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE (c.TodayIn > 0 OR c.TodayOut > 0)\nORDER BY c.TodayIn + c.TodayOut DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- 公司账户与客户账户通过 `AccountType` 区分\n- `TodayIn/TodayOut` 记录现金流动", "question_en": "List all cash movements between house and client accounts today.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q23", "question_zh": "列出所有逾期未付保证金利息的账户。", "sql": "-- 查询逾期保证金利息账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.LoanInterestMarginOverdue AS MarginOverdueInterest,\n c.LoanInterestMarginBOverdue AS MarginBOverdueInterest,\n c.LoanInterestOverdue AS GeneralOverdueInterest\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.LoanInterestMarginOverdue > 0 \n OR c.LoanInterestMarginBOverdue > 0\n OR c.LoanInterestOverdue > 0\nORDER BY (c.LoanInterestMarginOverdue + c.LoanInterestMarginBOverdue + c.LoanInterestOverdue) DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `LoanInterestMarginOverdue` 保证金账户逾期利息\n- `LoanInterestMarginBOverdue` B类保证金逾期利息", "question_en": "Show all accounts with overdue margin interest payments.", "rating": 8, "execution_result": null, "result_note": "当前查询无逾期利息记录", "tags": ["join", "ordering", "margin", "filter", "account", "interest"], "difficulty": "hard"}
{"qid": "Q26", "question_zh": "本月各交易所的结算费用明细如何?", "sql": "-- 按交易所统计结算费用 (2026年4月)\n-- 说明:BCAccountInstrument 表中 TotalBoughtFee/TotalSoldFee 是持仓级别的交易费用字段\n-- LastTransactionDate 表示该持仓最后交易日期\n-- 查询逻辑:筛选最后交易日期在本月内的持仓记录,按交易所汇总交易费用\nSELECT \n bi.MarketID,\n m.MarketName,\n SUM(bi.TotalBoughtFee) AS TotalBuyFee,\n SUM(bi.TotalSoldFee) AS TotalSellFee,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalSettlementFee,\n COUNT(DISTINCT bi.AccountID) AS TradingAccountCount\nFROM BCAccountInstrument bi\nINNER JOIN MCMarket m ON bi.MarketID = m.MarketID\nWHERE bi.LastTransactionDate >= '2026-04-01' AND bi.LastTransactionDate < '2026-05-01'\nGROUP BY bi.MarketID, m.MarketName\nORDER BY TotalSettlementFee DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCMarket": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.MarketID = m.MarketID"}]}, "explanation": "- `BCAccountInstrument` 存储持仓级别信息,包含各持仓的交易费用累计\n- `MCMarket` 存储市场信息,提供市场名称\n- `LastTransactionDate` 用于过滤本月有交易的持仓记录\n- 按市场分组汇总结算费用", "question_en": "What is the breakdown of settlement fees by exchange for this month?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "trade", "aggregation", "date_range"], "difficulty": "hard"}
{"qid": "Q28", "question_zh": "哪些客户已请求更改结算货币?", "sql": "-- 查询请求更改结算货币的客户\n-- 说明:经查 MCAccountCurrency 表无 CurrencyChangeStatus/RequestedCurrencyID 等字段\n-- 数据库中没有专门的货币变更请求表\n-- 此查询基于账户货币历史时间表(HCAccountCurrencyTimetable)展示货币生效安排\nSELECT \n act.AccountID,\n mca.Name AS AccountName,\n act.CurrencyID AS Currency,\n act.EffectiveDateFrom,\n act.EffectiveDateTo,\n act.AccountTypeID\nFROM HCAccountCurrencyTimetable act\nINNER JOIN MCAccount mca ON act.AccountID = mca.AccountID\nWHERE act.EffectiveDateTo IS NULL\nORDER BY act.EffectiveDateFrom DESC;", "schema_info": {"tables": {"HCAccountCurrencyTimetable": {"alias": "act", "columns": []}, "MCAccount": {"alias": "mca", "columns": []}}, "joins": [{"type": "INNER", "on": "act.AccountID = mca.AccountID"}]}, "explanation": "- `HCAccountCurrencyTimetable` 记录账户货币生效时间表\n- `EffectiveDateTo IS NULL` 表示当前生效的货币配置\n- 如需货币变更请求功能,建议在系统中扩展相关表结构", "question_en": "Which clients have requested a change in settlement currency?", "rating": 4, "execution_result": null, "result_note": "**说明:** 数据库中没有专门的货币变更请求表。`MCAccountCurrency` 表仅记录账户当前货币配置,无变更请求字段。", "tags": ["join", "account", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q33", "question_zh": "今日是否有追缴保证金通知?", "sql": "-- 查询今日追缴保证金记录 (固定日期: 2026-04-02)\nSELECT \n m.AccountID,\n a.Name AS AccountName,\n m.CallForDeposit,\n m.CallForDepositDate,\n m.CallForDepositDays\nFROM HCAccountMarginCallForDeposit m\nINNER JOIN MCAccount a ON m.AccountID = a.AccountID\nWHERE m.CallForDepositDate = '2026-04-02';", "schema_info": {"tables": {"HCAccountMarginCallForDeposit": {"alias": "m", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "m.AccountID = a.AccountID"}]}, "explanation": "- `HCAccountMarginCallForDeposit` 记录追缴保证金信息\n- `CallForDeposit` 追缴金额", "question_en": "Have there been any margin calls today?", "rating": 9, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "margin", "filter"], "difficulty": "easy"}
{"qid": "Q35", "question_zh": "列出本月按客户主任分组的佣金总额,以及相应的成交金额和返佣金额。", "sql": "-- 按经纪商/客户主任分组的佣金统计\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee) AS TotalBuyCommission,\n SUM(bi.TotalSoldFee) AS TotalSellCommission,\n SUM(bi.TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(bi.TotalSoldConsideration) AS TotalSellConsideration,\n SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE a.State = 'A'\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCAccount.AEID` 关联经纪商/客户主任\n- `BCAccountInstrument` 包含交易费用数据", "question_en": "List the total commission received this month by AE, along with corresponding consideration and rebate amounts.", "rating": 8, "execution_result": null, "result_note": "| AEID | AEName | AccountCount | TotalBuyCommission | TotalSellCommission | TotalCommission |\n|------|--------|-------------|-------------------|--------------------|----------------|\n| C01 | CHAN YUET HUNG | 628 | 183,244.64 | 187,220.59 | 370,465.23 |\n| C28 | CHAN SHU SHAN | 405 | 179,275.89 | 176,760.39 | 356,036.28 |\n| C05 | CENTRAL | 517 | 97,368.51 | 102,819.88 | 200,188.39 |\n| C33 | LEON NG | 13 | 71,541.06 | 72,620.60 | 144,161.66 |\n| C07 | CHAN WING PAI | 75 | 73,255.68 | 69,115.58 | 142,371.26 |\n| C10 | TOKWAWAN / KOWLOON CITY | 369 | 51,059.78 | 57,288.86 | 108,348.64 |\n| C08 | WONG HON KONG | 380 | 47,505.15 | 46,300.39 | 93,805.54 |\n| C36 | Name Of C36 | 146 | 40,945.66 | 35,682.86 | 76,628.52 |\n| C66 | CHEUNG YUK LING IVA | 17 | 24,458.82 | 22,723.18 | 47,182.00 |\n| C19 | WONG LO SING | 60 | 13,337.69 | 13,912.30 | 27,249.99 |\n\n(共15个AE有佣金记录,以上展示前10条)\n\n**注:** 当前SQL无日期条件,统计所有历史累计佣金。如需\"本月\"佣金,需添加 `LastTransactionDate >= '2026-04-01'` 条件。", "tags": ["join", "ordering", "filter", "account", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q37", "question_zh": "是否有正在进行的IPO事件,其认购状态如何?", "sql": "-- 查询进行中的IPO (2026年4月)\nSELECT \n i.InstrumentID,\n i.MarketID,\n i.Name AS InstrumentName,\n i.State AS InstrumentStatus,\n ip.Quantity AS SubscriptionLot,\n ip.SubscriptionAmount,\n ip.CreatedOn AS SubscriptionDate\nFROM MCInstrument i\nINNER JOIN MCInstrumentIPODetail ip ON i.InstrumentID = ip.InstrumentID\nWHERE YEAR(ip.CreatedOn) = 2026\n AND MONTH(ip.CreatedOn) = 4\nORDER BY ip.CreatedOn DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "i", "columns": []}, "MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": [{"type": "INNER", "on": "i.InstrumentID = ip.InstrumentID"}]}, "explanation": "- `MCInstrument` 表记录证券信息\n- `MCInstrumentIPODetail` 记录IPO认购详情", "question_en": "Are there any IPO events currently in progress, and what is their subscription status?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "filter", "ipo", "ordering"], "difficulty": "easy"}
{"qid": "Q39", "question_zh": "列出今日需要执行的公司行动(如权益分派)。", "sql": "-- 查询今日生效的公司行动 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.MarketID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.BalanceDate,\n e.BalanceExDate,\n e.Remark,\n e.State\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.State = 'A'\n AND (\n e.BalanceDate = '2026-04-02'\n OR e.BalanceExDate = '2026-04-02'\n OR e.AutoHoldDate = '2026-04-02'\n OR e.AutoDeductDate = '2026-04-02'\n );", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录所有权益分派信息\n- `BalanceDate` 权益登记日期", "question_en": "List corporate actions (e.g., entitlements) that need to be performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q41", "question_zh": "列出今日执行的所有现金划转。", "sql": "-- 今日现金变动汇总 (固定日期: 2026-04-02)\nSELECT \n b.AccountID,\n a.Name AS AccountName,\n b.TodayIn AS CashIn,\n b.TodayOut AS CashOut,\n b.BankAvailableBalance\nFROM BCAccountCash b\nINNER JOIN MCAccount a ON b.AccountID = a.AccountID\nWHERE b.TodayIn > 0 OR b.TodayOut > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "b", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "b.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash` 记录账户现金变动\n- `TodayIn` 今日现金流入", "question_en": "List all cash movements performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "filter", "cash"], "difficulty": "easy"}
{"qid": "Q45", "question_zh": "不同经纪商(如非中央结算系统持仓)的客户总持仓是多少?", "sql": "-- 按托管位置统计持仓(非CCASS)\nSELECT \n loc.LocationID,\n loc.Name AS LocationName,\n COUNT(DISTINCT bi.AccountID) AS AccountCount,\n SUM(bi.Settled) AS TotalQuantity,\n SUM(bi.CostAmount) AS TotalCostAmount\nFROM BCAccountLocationInstrument bi\nINNER JOIN MCLocation loc ON bi.LocationID = loc.LocationID\nWHERE loc.CCASSFlag = 'N'\nGROUP BY loc.LocationID, loc.Name\nORDER BY TotalQuantity DESC;", "schema_info": {"tables": {"BCAccountLocationInstrument": {"alias": "bi", "columns": []}, "MCLocation": {"alias": "loc", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.LocationID = loc.LocationID"}]}, "explanation": "- `BCAccountLocationInstrument` 记录按托管位置分类的持仓\n- `MCLocation` 存储托管位置信息", "question_en": "What is the total client holding at different broker firms (e.g., non-CCASS locations)?", "rating": 7, "execution_result": null, "result_note": "当前查询需要验证 Location 表关联", "tags": ["join", "ordering", "holding", "broker", "filter", "account", "aggregation"], "difficulty": "hard"}
{"qid": "Q46", "question_zh": "支付给其他经纪商的佣金是多少?", "sql": "-- 查询支付给其他经纪商的佣金\nSELECT \n b.BrokerID,\n b.Name AS BrokerName,\n SUM(bc.Commission) AS TotalCommission,\n SUM(bc.Consideration) AS TotalConsideration\nFROM MCBroker b\nINNER JOIN BCBrokerCash bc ON b.BrokerID = bc.BrokerID\nWHERE bc.Commission > 0\nGROUP BY b.BrokerID, b.Name\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCBroker": {"alias": "b", "columns": []}, "BCBrokerCash": {"alias": "bc", "columns": []}}, "joins": [{"type": "INNER", "on": "b.BrokerID = bc.BrokerID"}]}, "explanation": "- `MCBroker` 存储经纪商信息\n- `BCBrokerCash` 可能包含经纪商现金和佣金数据", "question_en": "How much commission has been paid to other brokers?", "rating": 6, "execution_result": null, "result_note": "当前查询需要验证经纪商佣金表关联", "tags": ["join", "ordering", "broker", "filter", "aggregation"], "difficulty": "hard"}
{"qid": "Q50", "question_zh": "", "sql": "SELECT TOP\n\t15 c.ContractID,\n\tc.TradeDate,\n\tLTRIM( RTRIM( c.AccountID ) ) AS AccountID,\n\tLTRIM( RTRIM( c.MarketID ) ) AS MarketID,\n\tc.InstrumentID,\n\tc.BuySell,\n\tc.Quantity,\n\tc.Consideration,\n\tLTRIM( RTRIM( c.CurrencyID ) ) AS CurrencyID \nFROM\n\tdbo.TSBAccountContract c\n\tINNER JOIN dbo.MCAccount a ON c.AccountID = a.AccountID \nWHERE\n\tCAST ( c.TradeDate AS DATE ) = '2026-04-02' \n\tAND LTRIM( RTRIM( a.HouseAccountFlag ) ) = 'N' \nORDER BY\n\tc.ContractID;", "schema_info": {"tables": {"TSBAccountContract": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "", "question_en": "列出今天所有客戶的交易記錄", "rating": null, "execution_result": null, "result_note": "| ContractID | TradeDate | AccountID | MarketID | InstrumentID | BuySell | Quantity | Consideration | CurrencyID |\n| :--------- | :--------- | :-------- | :------- | :----------- | :------ | :------- | :------------ | :--------- |\n| B02403846 | 2026-04-02 | P011206 | HKEX | 01810 | B | 600 | 18360 | HKD |\n| B02403847 | 2026-04-02 | P011202 | HKEX | 01810 | B | 200 | 6120 | HKD |\n\n\n\n\n\n---\n\n## 附录:关键表说明\n\n| 表名 | 说明 | 关键字段 |\n|------|------|---------|\n| MCAccount | 账户主表 | AccountID, Name, MarketValue, MarginFacilityFlag |\n| MCUser | 用户表 | UserID, Name, Status, LogonEnableFlag |\n| BCAccountInstrument | 账户持仓 | AccountID, MarketID, Settled, DueBuy, DueSell |\n| BCAccountCash | 账户现金 | AccountID, TodayIn, TodayOut, AccruedInterest |\n| HCAccountMarginCallForDeposit | 追缴保证金 | AccountID, CallForDeposit, CallForDepositDate |\n| MCInstrument | 证券表 | InstrumentID, Name, MarginPercentage |\n| MCInstrumentIPODetail | IPO详情 | InstrumentID, Quantity, SubscriptionAmount |\n| MSBEntitlement | 权益分派 | EntitlementID, BalanceDate, BalanceExDate |\n| MCBroker | 经纪商 | BrokerID, Name |\n| MCLocation | 托管位置 | LocationID, Name, CCASSFlag |\n| HCExchangeRate | 汇率 | ExchangeRateID, ValueDate |\n| HCAccountCashRecord | 现金记录 | AccountID, ValueDate, LedgerBalance |\n\n---\n\n**文档结束**", "tags": ["join", "limit", "filter", "ordering"], "difficulty": "easy"}
+4
View File
@@ -0,0 +1,4 @@
{"qid": "Q1", "question_zh": "按对手方列出截至[日期]的所有未结算交易。", "sql": "-- 按对手方统计截至 2026-04-02 的未结算交易\n-- 使用 TSBBrokerContract(经纪商合约表),按 BrokerID(对手方经纪商)分组\n-- SettleStatus='U' 表示未结算;CashSettleDate <= '2026-04-02' 筛选截至日\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n COUNT(*) AS UnsettledTradeCount,\n SUM(b.SettleQuantity) AS TotalUnsettledQty,\n SUM(b.SettleAmount) AS TotalUnsettledAmount,\n MIN(b.BuySell) + '~' + MAX(b.BuySell) AS BuySellRange,\n MIN(b.CashSettleDate) AS EarliestSettleDate,\n MAX(b.CashSettleDate) AS LatestSettleDate\nFROM TSBBrokerContract b\nLEFT JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.SettleStatus = 'U'\n AND b.CashSettleDate <= '2026-04-02'\nGROUP BY b.BrokerID, m.Name\nORDER BY TotalUnsettledAmount DESC;", "schema_info": {"tables": {"TSBBrokerContract": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "LEFT", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `TSBBrokerContract` 是经纪商/对手方合约表,记录与外部对手方的交易合约,`BrokerID` 即对手方标识\n- `SettleStatus = 'U'` 表示未结算;`CashSettleDate <= '2026-04-02'` 筛选截至日未结清的合约\n- 关联 `MCBroker` 获取对手方经纪商名称\n- 按 `BrokerID` 分组汇总未结算数量和金额", "question_en": "Show all unsettled trades as of [date] grouped by counterparty.", "rating": 9, "execution_result": null, "result_note": "| BrokerID | BrokerName | UnsettledTradeCount | TotalUnsettledQty | TotalUnsettledAmount | BuySellRange | EarliestSettleDate | LatestSettleDate |\n|----------|-----------|---------------------|-------------------|---------------------|--------------|---------------------|-------------------|\n| CCASS | CCASS | 622 | 40,459,253 | 44,173,571.06 | B~S | 2025-07-30 | 2026-04-02 |\n\n> **注**:CCASS(Hong Kong Securities Clearing Company Limited)是香港交易所的中央结算机构,作为交易所交易的核心对手方。622笔未结算合约均为 HKEX 市场。", "tags": ["join", "ordering", "broker", "filter", "trade", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q2", "question_zh": "列出今日所有客户账户之间的股票转移记录。", "sql": "-- 查询今日客户账户间股票转移(参考日期:2026-04-02)\n-- 使用 TSBAccountInstrumentMovement,MovementType='T' 表示账户间转移\n-- ValueDate 为转移生效日期,关联 MCInstrument 获取证券名称\nSELECT \n m.MovementID,\n m.AccountID AS FromAccountID,\n m.TransferToAccountID,\n m.InstrumentID,\n i.Name AS InstrumentSymbol,\n m.MovementType,\n m.Quantity AS TransferQuantity,\n m.ValueDate AS TransferDate\nFROM TSBAccountInstrumentMovement m\nLEFT JOIN MCInstrument i ON m.InstrumentID = i.InstrumentID\nWHERE m.MovementType = 'T'\n AND m.ValueDate = '2026-04-02'\nORDER BY m.ValueDate;", "schema_info": {"tables": {"TSBAccountInstrumentMovement": {"alias": "m", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "LEFT", "on": "m.InstrumentID = i.InstrumentID"}]}, "explanation": "- `TSBAccountInstrumentMovement` 是持仓变动流水表,记录所有证券变动事件\n- `MovementType = 'T'`(Transfer)特指**账户间股票转移**,对应 `TransferToAccountID` 记录目标账户\n- `ValueDate` 是转移生效日期,可按日期过滤\n- 关联 `MCInstrument` 获取证券代码/名称\n- 注意:`BCAccountInstrument` 的 `TodayIn/TodayOut` 是**实时快照**,不带历史日期维度,不能用于查历史转移", "question_en": "List all stock transfers between client accounts performed today.", "rating": 9, "execution_result": null, "result_note": "当前查询无结果(测试环境中 `TSBAccountInstrumentMovement` 的 `MovementType='T'` 最新记录为 2025-10-21,无 2026-04-02 的账户间转移数据)", "tags": ["join", "ordering", "filter", "account", "left_join"], "difficulty": "hard"}
{"qid": "Q15", "question_zh": "本月应付给介绍经纪人的佣金返佣总额是多少?", "sql": "-- 查询本月应付返佣 (2026年4月)\n-- 注意:BCAccountInstrument 无 UpdatedAt 字段,用 LastTransactionDate 过滤本月有交易的账户\n-- 说明:TotalBoughtFee/TotalSoldFee 为历史累计字段,此处统计近期活跃账户的累计佣金供参考\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE YEAR(bi.LastTransactionDate) = 2026\n AND MONTH(bi.LastTransactionDate) = 4\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee + bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCRebateScheme` 可能存储返佣规则\n- 按AE汇总佣金", "question_en": "What is the total commission rebate payable to introducing brokers this month?", "rating": 6, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q35", "question_zh": "列出本月按客户主任分组的佣金总额,以及相应的成交金额和返佣金额。", "sql": "-- 按经纪商/客户主任分组的佣金统计\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee) AS TotalBuyCommission,\n SUM(bi.TotalSoldFee) AS TotalSellCommission,\n SUM(bi.TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(bi.TotalSoldConsideration) AS TotalSellConsideration,\n SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE a.State = 'A'\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCAccount.AEID` 关联经纪商/客户主任\n- `BCAccountInstrument` 包含交易费用数据", "question_en": "List the total commission received this month by AE, along with corresponding consideration and rebate amounts.", "rating": 8, "execution_result": null, "result_note": "| AEID | AEName | AccountCount | TotalBuyCommission | TotalSellCommission | TotalCommission |\n|------|--------|-------------|-------------------|--------------------|----------------|\n| C01 | CHAN YUET HUNG | 628 | 183,244.64 | 187,220.59 | 370,465.23 |\n| C28 | CHAN SHU SHAN | 405 | 179,275.89 | 176,760.39 | 356,036.28 |\n| C05 | CENTRAL | 517 | 97,368.51 | 102,819.88 | 200,188.39 |\n| C33 | LEON NG | 13 | 71,541.06 | 72,620.60 | 144,161.66 |\n| C07 | CHAN WING PAI | 75 | 73,255.68 | 69,115.58 | 142,371.26 |\n| C10 | TOKWAWAN / KOWLOON CITY | 369 | 51,059.78 | 57,288.86 | 108,348.64 |\n| C08 | WONG HON KONG | 380 | 47,505.15 | 46,300.39 | 93,805.54 |\n| C36 | Name Of C36 | 146 | 40,945.66 | 35,682.86 | 76,628.52 |\n| C66 | CHEUNG YUK LING IVA | 17 | 24,458.82 | 22,723.18 | 47,182.00 |\n| C19 | WONG LO SING | 60 | 13,337.69 | 13,912.30 | 27,249.99 |\n\n(共15个AE有佣金记录,以上展示前10条)\n\n**注:** 当前SQL无日期条件,统计所有历史累计佣金。如需\"本月\"佣金,需添加 `LastTransactionDate >= '2026-04-01'` 条件。", "tags": ["join", "ordering", "filter", "account", "left_join", "aggregation"], "difficulty": "hard"}
+5
View File
@@ -0,0 +1,5 @@
{"qid": "Q17", "question_zh": "哪些客户已超过其信用额度?", "sql": "-- 查询超信用额度客户(使用 MarginLimit)\n-- 注意:MCAccount 无 CreditLimit 字段,应用 MarginLimit\nSELECT \n AccountID,\n Name AS AccountName,\n MarginLimit,\n MarketValue,\n MarginLimit - MarketValue AS AvailableCredit,\n CASE \n WHEN MarketValue > MarginLimit THEN '超额'\n WHEN MarketValue > MarginLimit * 0.8 THEN '接近限额'\n ELSE '正常'\n END AS Status\nFROM MCAccount\nWHERE MarginLimit > 0\n AND MarketValue > MarginLimit * 0.8\nORDER BY (MarketValue - MarginLimit) DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.MarginLimit` 保证金/信用限额(注意:无 `CreditLimit` 字段)\n- `MCAccount.MarketValue` 持仓市值\n- `MarginBLimit` 是单独借款限额,注意区分", "question_en": "Which clients have exceeded their credit limit?", "rating": 7, "execution_result": null, "result_note": "当前查询无超限客户", "tags": ["account", "limit", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q34", "question_zh": "保证金账户前20大持仓(按市值)是多少?", "sql": "-- 保证金账户按市值排序的前20持仓\nSELECT TOP 20\n a.AccountID,\n a.Name AS AccountName,\n a.MarketValue,\n a.MarginDebitRatio AS MarginDebitBalanceRatio,\n a.MarginPosition,\n a.CallForDeposit,\n a.MarginFacilityFlag\nFROM MCAccount a\nWHERE a.MarginFacilityFlag = 'Y'\n AND a.State = 'A'\n AND a.MarketValue > 0\nORDER BY a.MarketValue DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 表包含所有账户信息\n- `MarginFacilityFlag = 'Y'` 筛选保证金账户", "question_en": "What are the top 20 holdings (based on market value) for margin accounts?", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginPosition |\n|-----------|-------------|------------|----------------|\n| M050009 | NG SUN SHU*** | 57,420,000 | 35,515,021.58 |\n| M050013 | NG CHUNG WAI*** | 19,504,520 | 10,918,958.78 |\n| M050193 | WONG KING YIU*** ^ | 11,682,920 | 3,340,099.05 |\n| P020160 | LAW SHIU MING DENNIS | 7,520,370 | 0 |\n| P030078 | MAK SUI BING | 7,120,309.94 | 0 |\n| P051101 | CHUNG CHUNG YEE | 7,117,808.04 | 0 |\n| M050170 | FUNG LAI FONG ANNA | 7,009,227.25 | 4,136,857 |\n| P220005 | LAI KAM SUI # | 5,837,102.10 | 97.97 |\n| P280628 | CHAN KWOK MO # | 5,761,997.48 | 62,508.23 |\n| P280455 | LEUNG KA CHI # | 5,487,971.20 | -64,981.22 |\n\n(共20条记录,以上展示前10条)", "tags": ["ordering", "holding", "margin", "filter", "limit", "account"], "difficulty": "hard"}
{"qid": "Q48", "question_zh": "列出所有支持保证金的证券及其相应的保证金比例。", "sql": "-- 查询支持保证金的证券\nSELECT \n InstrumentID,\n Name AS InstrumentName,\n MarginPercentage AS MarginRatio,\n CASE \n WHEN MarginPercentage >= 0.7 THEN '高'\n WHEN MarginPercentage >= 0.5 THEN '中'\n WHEN MarginPercentage > 0 THEN '低'\n ELSE 'N/A'\n END AS RiskLevel,\n MarginLimitPerInstrument,\n CollateralRatio\nFROM MCInstrument\nWHERE MarginPercentage IS NOT NULL\n AND MarginPercentage > 0\n AND State = 'A'\nORDER BY MarginPercentage DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "MCInstrument", "columns": []}}, "joins": []}, "explanation": "- `MCInstrument` 存储证券信息\n- `MarginPercentage` 保证金比例", "question_en": "List all instruments that support margin and their corresponding margin ratios.", "rating": 9, "execution_result": null, "result_note": "| InstrumentID | InstrumentName | MarginRatio | RiskLevel |\n|-------------|----------------|-------------|-----------|\n| 00001 | CKH HOLDINGS(S) | 0.70 | 高 |\n| 00002 | CLP HOLDINGS(S) | 0.70 | 高 |\n| 00003 | HK & CHINA GAS(S) | 0.70 | 高 |\n\n(共767条记录)", "tags": ["margin", "limit", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q49", "question_zh": "本月、本季度和今年分别开了多少账户?", "sql": "-- 开户统计 (2026年4月)\nSELECT \n COUNT(CASE WHEN MONTH(OpenDate) = 4 AND YEAR(OpenDate) = 2026 THEN 1 END) AS April2026,\n COUNT(CASE WHEN DATEPART(QUARTER, OpenDate) = 2 AND YEAR(OpenDate) = 2026 THEN 1 END) AS Q2_2026,\n COUNT(CASE WHEN YEAR(OpenDate) = 2026 THEN 1 END) AS Year2026,\n COUNT(*) AS TotalAccounts,\n MIN(OpenDate) AS EarliestOpenDate,\n MAX(OpenDate) AS LatestOpenDate\nFROM MCAccount\nWHERE OpenDate IS NOT NULL;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.OpenDate` 账户开户日期\n- 按月、季度、年分别统计新开户数量", "question_en": "How many accounts were opened this month, this quarter, and this year?", "rating": 9, "execution_result": null, "result_note": "| April2026 | Q2_2026 | Year2026 | TotalAccounts | EarliestOpenDate | LatestOpenDate |\n|-----------|---------|----------|---------------|------------------|----------------|\n| 0 | 0 | 0 | 1,951 | 1993-03-05 | 2025-10-16 |", "tags": ["account", "limit", "filter", "aggregation"], "difficulty": "easy"}
{"qid": "Q50", "question_zh": "", "sql": "SELECT TOP\n\t15 c.ContractID,\n\tc.TradeDate,\n\tLTRIM( RTRIM( c.AccountID ) ) AS AccountID,\n\tLTRIM( RTRIM( c.MarketID ) ) AS MarketID,\n\tc.InstrumentID,\n\tc.BuySell,\n\tc.Quantity,\n\tc.Consideration,\n\tLTRIM( RTRIM( c.CurrencyID ) ) AS CurrencyID \nFROM\n\tdbo.TSBAccountContract c\n\tINNER JOIN dbo.MCAccount a ON c.AccountID = a.AccountID \nWHERE\n\tCAST ( c.TradeDate AS DATE ) = '2026-04-02' \n\tAND LTRIM( RTRIM( a.HouseAccountFlag ) ) = 'N' \nORDER BY\n\tc.ContractID;", "schema_info": {"tables": {"TSBAccountContract": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "", "question_en": "列出今天所有客戶的交易記錄", "rating": null, "execution_result": null, "result_note": "| ContractID | TradeDate | AccountID | MarketID | InstrumentID | BuySell | Quantity | Consideration | CurrencyID |\n| :--------- | :--------- | :-------- | :------- | :----------- | :------ | :------- | :------------ | :--------- |\n| B02403846 | 2026-04-02 | P011206 | HKEX | 01810 | B | 600 | 18360 | HKD |\n| B02403847 | 2026-04-02 | P011202 | HKEX | 01810 | B | 200 | 6120 | HKD |\n\n\n\n\n\n---\n\n## 附录:关键表说明\n\n| 表名 | 说明 | 关键字段 |\n|------|------|---------|\n| MCAccount | 账户主表 | AccountID, Name, MarketValue, MarginFacilityFlag |\n| MCUser | 用户表 | UserID, Name, Status, LogonEnableFlag |\n| BCAccountInstrument | 账户持仓 | AccountID, MarketID, Settled, DueBuy, DueSell |\n| BCAccountCash | 账户现金 | AccountID, TodayIn, TodayOut, AccruedInterest |\n| HCAccountMarginCallForDeposit | 追缴保证金 | AccountID, CallForDeposit, CallForDepositDate |\n| MCInstrument | 证券表 | InstrumentID, Name, MarginPercentage |\n| MCInstrumentIPODetail | IPO详情 | InstrumentID, Quantity, SubscriptionAmount |\n| MSBEntitlement | 权益分派 | EntitlementID, BalanceDate, BalanceExDate |\n| MCBroker | 经纪商 | BrokerID, Name |\n| MCLocation | 托管位置 | LocationID, Name, CCASSFlag |\n| HCExchangeRate | 汇率 | ExchangeRateID, ValueDate |\n| HCAccountCashRecord | 现金记录 | AccountID, ValueDate, LedgerBalance |\n\n---\n\n**文档结束**", "tags": ["join", "limit", "filter", "ordering"], "difficulty": "easy"}
+7
View File
@@ -0,0 +1,7 @@
{"qid": "Q5", "question_zh": "列出今日发出的所有追收保证金通知及其回复状态。", "sql": "-- 查询今日追缴保证金记录 (参考日期: 2026-04-02)\n-- 使用 MCAccount 的账户级追缴字段(CallForDepositDate = 追缴通知发出日期)\n-- 注意:HCAccountMarginCallForDeposit 是追缴每日快照表,不含\"通知发出日\"字段\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n a.CallForDeposit AS CallAmount,\n a.CallForDepositDate AS IssueDate,\n a.CallForDepositDays AS OverdueDays\nFROM MCAccount a\nWHERE a.CallForDepositDate = '2026-04-02'\nORDER BY a.CallForDeposit DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.CallForDepositDate` = 追缴通知发出日期,`CallForDeposit` = 追缴金额\n- `CallForDeposit < 0` 表示已结清;如查活跃追缴,应筛选 `CallForDeposit > 0`\n- `HCAccountMarginCallForDeposit` 是追缴每日历史快照,不适合查询\"今日发出的通知\"\n- `CallStatus` 字段在 `HCAccountMarginCallForDeposit` 中不存在", "question_en": "Show all margin calls issued today and their response status.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果(测试环境中 MCAccount 的 `CallForDepositDate` 最新到 2025-10-31,2026-04-02 无追缴通知记录)\n\n> 注:`MCAccount.CallForDeposit` 当前所有值均为负数(已结清的追缴金额),无活跃追缴记录。", "tags": ["margin", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q19", "question_zh": "列出今日起保证金比例发生变动的所有证券。", "sql": "-- 查询保证金比例变动的证券 (固定日期: 2026-04-02)\nSELECT \n i.InstrumentID,\n i.Name AS InstrumentName,\n i.MarginPercentage AS CurrentMarginRatio,\n i.MarginChangeDate\nFROM MCInstrument i\nWHERE i.MarginChangeDate = '2026-04-02'\nORDER BY i.MarginPercentage DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "i", "columns": []}}, "joins": []}, "explanation": "- `MCInstrument.MarginPercentage` 当前保证金比例\n- `MarginChangeDate` 变动日期", "question_en": "List all instruments with margin ratio changes effective today.", "rating": 7, "execution_result": null, "result_note": "当前查询无保证金比例变动记录", "tags": ["margin", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q23", "question_zh": "列出所有逾期未付保证金利息的账户。", "sql": "-- 查询逾期保证金利息账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.LoanInterestMarginOverdue AS MarginOverdueInterest,\n c.LoanInterestMarginBOverdue AS MarginBOverdueInterest,\n c.LoanInterestOverdue AS GeneralOverdueInterest\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.LoanInterestMarginOverdue > 0 \n OR c.LoanInterestMarginBOverdue > 0\n OR c.LoanInterestOverdue > 0\nORDER BY (c.LoanInterestMarginOverdue + c.LoanInterestMarginBOverdue + c.LoanInterestOverdue) DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `LoanInterestMarginOverdue` 保证金账户逾期利息\n- `LoanInterestMarginBOverdue` B类保证金逾期利息", "question_en": "Show all accounts with overdue margin interest payments.", "rating": 8, "execution_result": null, "result_note": "当前查询无逾期利息记录", "tags": ["join", "ordering", "margin", "filter", "account", "interest"], "difficulty": "hard"}
{"qid": "Q33", "question_zh": "今日是否有追缴保证金通知?", "sql": "-- 查询今日追缴保证金记录 (固定日期: 2026-04-02)\nSELECT \n m.AccountID,\n a.Name AS AccountName,\n m.CallForDeposit,\n m.CallForDepositDate,\n m.CallForDepositDays\nFROM HCAccountMarginCallForDeposit m\nINNER JOIN MCAccount a ON m.AccountID = a.AccountID\nWHERE m.CallForDepositDate = '2026-04-02';", "schema_info": {"tables": {"HCAccountMarginCallForDeposit": {"alias": "m", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "m.AccountID = a.AccountID"}]}, "explanation": "- `HCAccountMarginCallForDeposit` 记录追缴保证金信息\n- `CallForDeposit` 追缴金额", "question_en": "Have there been any margin calls today?", "rating": 9, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "margin", "filter"], "difficulty": "easy"}
{"qid": "Q34", "question_zh": "保证金账户前20大持仓(按市值)是多少?", "sql": "-- 保证金账户按市值排序的前20持仓\nSELECT TOP 20\n a.AccountID,\n a.Name AS AccountName,\n a.MarketValue,\n a.MarginDebitRatio AS MarginDebitBalanceRatio,\n a.MarginPosition,\n a.CallForDeposit,\n a.MarginFacilityFlag\nFROM MCAccount a\nWHERE a.MarginFacilityFlag = 'Y'\n AND a.State = 'A'\n AND a.MarketValue > 0\nORDER BY a.MarketValue DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 表包含所有账户信息\n- `MarginFacilityFlag = 'Y'` 筛选保证金账户", "question_en": "What are the top 20 holdings (based on market value) for margin accounts?", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginPosition |\n|-----------|-------------|------------|----------------|\n| M050009 | NG SUN SHU*** | 57,420,000 | 35,515,021.58 |\n| M050013 | NG CHUNG WAI*** | 19,504,520 | 10,918,958.78 |\n| M050193 | WONG KING YIU*** ^ | 11,682,920 | 3,340,099.05 |\n| P020160 | LAW SHIU MING DENNIS | 7,520,370 | 0 |\n| P030078 | MAK SUI BING | 7,120,309.94 | 0 |\n| P051101 | CHUNG CHUNG YEE | 7,117,808.04 | 0 |\n| M050170 | FUNG LAI FONG ANNA | 7,009,227.25 | 4,136,857 |\n| P220005 | LAI KAM SUI # | 5,837,102.10 | 97.97 |\n| P280628 | CHAN KWOK MO # | 5,761,997.48 | 62,508.23 |\n| P280455 | LEUNG KA CHI # | 5,487,971.20 | -64,981.22 |\n\n(共20条记录,以上展示前10条)", "tags": ["ordering", "holding", "margin", "filter", "limit", "account"], "difficulty": "hard"}
{"qid": "Q38", "question_zh": "本月IPO事件的总佣金、手续费和保证金利息是多少?", "sql": "-- IPO相关费用汇总 (2026年4月)\nSELECT \n 'IPO Commission' AS FeeType,\n SUM(ip.SubscriptionAmount * 0.001) AS EstimatedFee\nFROM MCInstrumentIPODetail ip\nWHERE YEAR(ip.CreatedOn) = 2026\n AND MONTH(ip.CreatedOn) = 4;", "schema_info": {"tables": {"MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": []}, "explanation": "- IPO相关费用分散在多个表中\n- 需要关联 `BCAccountInstrument` 获取IPO交易费用", "question_en": "What are the total commission, handling fees, and margin interest for IPO events this month?", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["margin", "aggregation", "filter", "interest"], "difficulty": "easy"}
{"qid": "Q48", "question_zh": "列出所有支持保证金的证券及其相应的保证金比例。", "sql": "-- 查询支持保证金的证券\nSELECT \n InstrumentID,\n Name AS InstrumentName,\n MarginPercentage AS MarginRatio,\n CASE \n WHEN MarginPercentage >= 0.7 THEN '高'\n WHEN MarginPercentage >= 0.5 THEN '中'\n WHEN MarginPercentage > 0 THEN '低'\n ELSE 'N/A'\n END AS RiskLevel,\n MarginLimitPerInstrument,\n CollateralRatio\nFROM MCInstrument\nWHERE MarginPercentage IS NOT NULL\n AND MarginPercentage > 0\n AND State = 'A'\nORDER BY MarginPercentage DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "MCInstrument", "columns": []}}, "joins": []}, "explanation": "- `MCInstrument` 存储证券信息\n- `MarginPercentage` 保证金比例", "question_en": "List all instruments that support margin and their corresponding margin ratios.", "rating": 9, "execution_result": null, "result_note": "| InstrumentID | InstrumentName | MarginRatio | RiskLevel |\n|-------------|----------------|-------------|-----------|\n| 00001 | CKH HOLDINGS(S) | 0.70 | 高 |\n| 00002 | CLP HOLDINGS(S) | 0.70 | 高 |\n| 00003 | HK & CHINA GAS(S) | 0.70 | 高 |\n\n(共767条记录)", "tags": ["margin", "limit", "filter", "ordering"], "difficulty": "easy"}
+34
View File
@@ -0,0 +1,34 @@
{"qid": "Q1", "question_zh": "按对手方列出截至[日期]的所有未结算交易。", "sql": "-- 按对手方统计截至 2026-04-02 的未结算交易\n-- 使用 TSBBrokerContract(经纪商合约表),按 BrokerID(对手方经纪商)分组\n-- SettleStatus='U' 表示未结算;CashSettleDate <= '2026-04-02' 筛选截至日\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n COUNT(*) AS UnsettledTradeCount,\n SUM(b.SettleQuantity) AS TotalUnsettledQty,\n SUM(b.SettleAmount) AS TotalUnsettledAmount,\n MIN(b.BuySell) + '~' + MAX(b.BuySell) AS BuySellRange,\n MIN(b.CashSettleDate) AS EarliestSettleDate,\n MAX(b.CashSettleDate) AS LatestSettleDate\nFROM TSBBrokerContract b\nLEFT JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.SettleStatus = 'U'\n AND b.CashSettleDate <= '2026-04-02'\nGROUP BY b.BrokerID, m.Name\nORDER BY TotalUnsettledAmount DESC;", "schema_info": {"tables": {"TSBBrokerContract": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "LEFT", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `TSBBrokerContract` 是经纪商/对手方合约表,记录与外部对手方的交易合约,`BrokerID` 即对手方标识\n- `SettleStatus = 'U'` 表示未结算;`CashSettleDate <= '2026-04-02'` 筛选截至日未结清的合约\n- 关联 `MCBroker` 获取对手方经纪商名称\n- 按 `BrokerID` 分组汇总未结算数量和金额", "question_en": "Show all unsettled trades as of [date] grouped by counterparty.", "rating": 9, "execution_result": null, "result_note": "| BrokerID | BrokerName | UnsettledTradeCount | TotalUnsettledQty | TotalUnsettledAmount | BuySellRange | EarliestSettleDate | LatestSettleDate |\n|----------|-----------|---------------------|-------------------|---------------------|--------------|---------------------|-------------------|\n| CCASS | CCASS | 622 | 40,459,253 | 44,173,571.06 | B~S | 2025-07-30 | 2026-04-02 |\n\n> **注**:CCASS(Hong Kong Securities Clearing Company Limited)是香港交易所的中央结算机构,作为交易所交易的核心对手方。622笔未结算合约均为 HKEX 市场。", "tags": ["join", "ordering", "broker", "filter", "trade", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q2", "question_zh": "列出今日所有客户账户之间的股票转移记录。", "sql": "-- 查询今日客户账户间股票转移(参考日期:2026-04-02)\n-- 使用 TSBAccountInstrumentMovement,MovementType='T' 表示账户间转移\n-- ValueDate 为转移生效日期,关联 MCInstrument 获取证券名称\nSELECT \n m.MovementID,\n m.AccountID AS FromAccountID,\n m.TransferToAccountID,\n m.InstrumentID,\n i.Name AS InstrumentSymbol,\n m.MovementType,\n m.Quantity AS TransferQuantity,\n m.ValueDate AS TransferDate\nFROM TSBAccountInstrumentMovement m\nLEFT JOIN MCInstrument i ON m.InstrumentID = i.InstrumentID\nWHERE m.MovementType = 'T'\n AND m.ValueDate = '2026-04-02'\nORDER BY m.ValueDate;", "schema_info": {"tables": {"TSBAccountInstrumentMovement": {"alias": "m", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "LEFT", "on": "m.InstrumentID = i.InstrumentID"}]}, "explanation": "- `TSBAccountInstrumentMovement` 是持仓变动流水表,记录所有证券变动事件\n- `MovementType = 'T'`(Transfer)特指**账户间股票转移**,对应 `TransferToAccountID` 记录目标账户\n- `ValueDate` 是转移生效日期,可按日期过滤\n- 关联 `MCInstrument` 获取证券代码/名称\n- 注意:`BCAccountInstrument` 的 `TodayIn/TodayOut` 是**实时快照**,不带历史日期维度,不能用于查历史转移", "question_en": "List all stock transfers between client accounts performed today.", "rating": 9, "execution_result": null, "result_note": "当前查询无结果(测试环境中 `TSBAccountInstrumentMovement` 的 `MovementType='T'` 最新记录为 2025-10-21,无 2026-04-02 的账户间转移数据)", "tags": ["join", "ordering", "filter", "account", "left_join"], "difficulty": "hard"}
{"qid": "Q3", "question_zh": "今日结算使用的汇率是多少?", "sql": "-- 查询汇率类型列表 (固定日期: 2026-04-02)\nSELECT \n ExchangeRateID, \n Name, \n NameEx\nFROM HCExchangeRate\nWHERE ValueDate = '2026-04-02'\nORDER BY ExchangeRateID;", "schema_info": {"tables": {"HCExchangeRate": {"alias": "HCExchangeRate", "columns": []}}, "joins": []}, "explanation": "- `HCExchangeRate` 存储汇率类型定义\n- `HCExchangeRateDetail` 存储各货币对的汇率值\n- 两个表通过 `ExchangeRateID` + `ValueDate` 关联\n- `ExchangeRateDirection` = 'D' 表示直接汇率", "question_en": "What are the currency exchange rates used for today's settlement?", "rating": 9, "execution_result": null, "result_note": "", "tags": ["exchange_rate", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q4", "question_zh": "哪些券商尚有未履行的交收义务?", "sql": "-- 查询有未履行交收义务的经纪商(截至 2026-04-02)\n-- Settled < 0 表示经纪商欠我们的现金(未履行交收义务)\n-- 注意:BCBrokerCash.Settled 是经纪商在我们账户的已结算现金余额,负数=经纪商欠款\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n b.CurrencyID,\n b.Settled AS OwedToUsAmount,\n ABS(b.Settled) AS OutstandingAmount\nFROM BCBrokerCash b\nINNER JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.Settled < 0\nORDER BY ABS(b.Settled) DESC;", "schema_info": {"tables": {"BCBrokerCash": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `BCBrokerCash` 记录经纪商在我们账户的结算现金,`Settled < 0` = 经纪商欠我们(未履行交收义务)\n- 关联 `MCBroker` 获取经纪商名称\n- 按欠款金额降序排列,优先处理大额欠款", "question_en": "Which brokers have outstanding delivery obligations to us?", "rating": 8, "execution_result": null, "result_note": "| BrokerID | BrokerName | CurrencyID | OwedToUsAmount | OutstandingAmount |\n|----------|-----------|------------|-----------------|-------------------|\n| CCASS | CCASS | CNY | -52,680.00 | 52,680.00 |\n| CCASS | CCASS | USD | -90.00 | 90.00 |\n\n> 注:CCASS 欠我们的结算现金(CNY 52,680 + USD 90)。HKD 余额为正(+4,202,811.87)表示我们欠 CCASS,不属于\"未履行交收义务\"范畴。", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q5", "question_zh": "列出今日发出的所有追收保证金通知及其回复状态。", "sql": "-- 查询今日追缴保证金记录 (参考日期: 2026-04-02)\n-- 使用 MCAccount 的账户级追缴字段(CallForDepositDate = 追缴通知发出日期)\n-- 注意:HCAccountMarginCallForDeposit 是追缴每日快照表,不含\"通知发出日\"字段\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n a.CallForDeposit AS CallAmount,\n a.CallForDepositDate AS IssueDate,\n a.CallForDepositDays AS OverdueDays\nFROM MCAccount a\nWHERE a.CallForDepositDate = '2026-04-02'\nORDER BY a.CallForDeposit DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.CallForDepositDate` = 追缴通知发出日期,`CallForDeposit` = 追缴金额\n- `CallForDeposit < 0` 表示已结清;如查活跃追缴,应筛选 `CallForDeposit > 0`\n- `HCAccountMarginCallForDeposit` 是追缴每日历史快照,不适合查询\"今日发出的通知\"\n- `CallStatus` 字段在 `HCAccountMarginCallForDeposit` 中不存在", "question_en": "Show all margin calls issued today and their response status.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果(测试环境中 MCAccount 的 `CallForDepositDate` 最新到 2025-10-31,2026-04-02 无追缴通知记录)\n\n> 注:`MCAccount.CallForDeposit` 当前所有值均为负数(已结清的追缴金额),无活跃追缴记录。", "tags": ["margin", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q6", "question_zh": "所有货币的客户现金总余额是多少?", "sql": "-- 按货币统计客户现金余额\nSELECT \n CurrencyID,\n COUNT(DISTINCT AccountID) AS AccountCount,\n SUM(Settled) AS TotalSettledBalance,\n SUM(AccruedCreditInterest) AS TotalCreditInterest,\n SUM(AccruedDebitInterest) AS TotalDebitInterest,\n SUM(Settled) + SUM(AccruedCreditInterest) - SUM(AccruedDebitInterest) AS NetBalance\nFROM BCAccountCash\nGROUP BY CurrencyID\nORDER BY NetBalance DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `BCAccountCash` 记录账户现金余额\n- `Settled` 已结算余额\n- `AccruedCreditInterest` 应计存款利息\n- `AccruedDebitInterest` 应计借款利息", "question_en": "What is the total client cash balance across all currencies?", "rating": 9, "execution_result": null, "result_note": "| CurrencyID | AccountCount | TotalSettledBalance | NetBalance |\n|------------|-------------|--------------------|------------|\n| HKD | 2,906 | 52,195,305.77 | 52,195,305.77 |\n| TWD | 2 | -27,676.60 | -27,676.60 |\n| USD | 175 | 0 | 0 |\n| CNY | 95 | 0 | 0 |\n| GBP | 1 | 0 | 0 |", "tags": ["ordering", "account", "cash", "aggregation"], "difficulty": "medium"}
{"qid": "Q7", "question_zh": "今日结算后现金余额为负的账户列表。", "sql": "-- 查询现金余额为负的账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.Settled AS CashBalance,\n c.UnderdueCheque,\n c.BankAvailableBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.Settled < 0\nORDER BY c.Settled ASC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash.Settled` 表示已结算现金余额\n- 负数表示账户透支\n- 关联 `MCAccount` 获取账户名称", "question_en": "List accounts with negative cash balance after today's settlement.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | CurrencyID | CashBalance |\n|-----------|------------|------------|-------------|\n| M050009 | NG SUN SHU*** | HKD | -4,678,978.42 |\n| P050667 | WONG YIM HUNG | HKD | -780,196.94 |\n| M050521 | LO CHUN YIP | HKD | -290,487.54 |\n\n(共55个账户现金余额为负)", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q9", "question_zh": "今日预计收到哪些股息?", "sql": "-- 查询今日预计收到的股息 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceDate AS PaymentDate,\n e.BalanceType,\n e.Remark AS DividendDetails\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.BalanceDate = '2026-04-02'\n AND e.BalanceType = 'C'\n AND e.State = 'A'\nORDER BY i.Name;", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录所有权益分派\n- `BalanceType = 'C'` 表示现金股息\n- `BalanceDate` 股息支付日期", "question_en": "What dividends are expected to be received today?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q10", "question_zh": "列出所有进行中IPO的待缴申购金额。", "sql": "-- 查询进行中IPO的待缴金额\nSELECT \n ip.InstrumentID,\n i.Name AS InstrumentName,\n i.State AS InstrumentStatus,\n ip.SubscriptionAmount,\n ip.SubscriptionPrice,\n ip.Quantity AS SubscriptionLot,\n ip.CreatedOn AS SubscriptionDate,\n ip.State AS SubscriptionStatus\nFROM MCInstrumentIPODetail ip\nINNER JOIN MCInstrument i ON ip.InstrumentID = i.InstrumentID\nWHERE ip.State = 'A'\n AND i.State = 'A'\nORDER BY ip.CreatedOn DESC;", "schema_info": {"tables": {"MCInstrumentIPODetail": {"alias": "ip", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "ip.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MCInstrumentIPODetail` 记录IPO认购详情\n- `SubscriptionAmount` 申购金额\n- `State = 'A'` 表示进行中", "question_en": "Show all pending subscription amounts for ongoing IPOs.", "rating": 8, "execution_result": null, "result_note": "| InstrumentID | InstrumentName | SubscriptionAmount | SubscriptionPrice | Quantity |\n|--------------|----------------|-------------------|-------------------|----------|\n| 02259 | HKEX | 7,231.19 | 36.16 | 100 |\n| 02259 | HKEX | 14,462.40 | 36.16 | 200 |\n\n> 注:MCInstrumentIPODetail 共 586 条进行中 IPO 记录(State='A'),以上为示例行。", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q11", "question_zh": "哪些客户尚未缴纳IPO申购款?", "sql": "-- 查询未缴纳IPO申购款的账户\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.TotalBoughtQuantity AS SubscriptionLot,\n bi.TotalBoughtConsideration AS SubscriptionAmount\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nINNER JOIN MCInstrumentIPODetail ip ON bi.InstrumentID = ip.InstrumentID\nWHERE ip.State = 'A'\n AND bi.TotalBoughtConsideration > 0\n AND bi.TotalBoughtFee = 0\nORDER BY bi.TotalBoughtConsideration DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}, "MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}, {"type": "INNER", "on": "bi.InstrumentID = ip.InstrumentID"}]}, "explanation": "- 通过比对买卖数量和手续费判断是否缴款\n- `TotalBoughtConsideration > 0` 有认购\n- `TotalBoughtFee = 0` 未支付手续费", "question_en": "Which clients have not yet paid their IPO subscription money?", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "ordering"], "difficulty": "hard"}
{"qid": "Q14", "question_zh": "列出已申请但尚未处理的客户提款请求。", "sql": "-- 查询待处理提款申请 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.TodayOut AS WithdrawalAmount,\n c.BankAvailableBalance AS AvailableBalance,\n c.State AS RecordStatus\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.TodayOut > 0\nORDER BY c.TodayOut DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `TodayOut` 今日计划支出\n- 待处理提款申请应体现在此字段", "question_en": "Show all client withdrawals requested but not yet processed.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q15", "question_zh": "本月应付给介绍经纪人的佣金返佣总额是多少?", "sql": "-- 查询本月应付返佣 (2026年4月)\n-- 注意:BCAccountInstrument 无 UpdatedAt 字段,用 LastTransactionDate 过滤本月有交易的账户\n-- 说明:TotalBoughtFee/TotalSoldFee 为历史累计字段,此处统计近期活跃账户的累计佣金供参考\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE YEAR(bi.LastTransactionDate) = 2026\n AND MONTH(bi.LastTransactionDate) = 4\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee + bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCRebateScheme` 可能存储返佣规则\n- 按AE汇总佣金", "question_en": "What is the total commission rebate payable to introducing brokers this month?", "rating": 6, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q17", "question_zh": "哪些客户已超过其信用额度?", "sql": "-- 查询超信用额度客户(使用 MarginLimit)\n-- 注意:MCAccount 无 CreditLimit 字段,应用 MarginLimit\nSELECT \n AccountID,\n Name AS AccountName,\n MarginLimit,\n MarketValue,\n MarginLimit - MarketValue AS AvailableCredit,\n CASE \n WHEN MarketValue > MarginLimit THEN '超额'\n WHEN MarketValue > MarginLimit * 0.8 THEN '接近限额'\n ELSE '正常'\n END AS Status\nFROM MCAccount\nWHERE MarginLimit > 0\n AND MarketValue > MarginLimit * 0.8\nORDER BY (MarketValue - MarginLimit) DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.MarginLimit` 保证金/信用限额(注意:无 `CreditLimit` 字段)\n- `MCAccount.MarketValue` 持仓市值\n- `MarginBLimit` 是单独借款限额,注意区分", "question_en": "Which clients have exceeded their credit limit?", "rating": 7, "execution_result": null, "result_note": "当前查询无超限客户", "tags": ["account", "limit", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q18", "question_zh": "今日收到的未清算支票总额是多少?", "sql": "-- 查询未清算支票 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.UnderdueCheque AS OverdueCheque,\n c.NextDayDueCheque AS PendingCheque,\n c.UnderdueCheque + c.NextDayDueCheque AS TotalUncleared\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE (c.UnderdueCheque > 0 OR c.NextDayDueCheque > 0) -- 注意:BCAccountCash 无这两个字段,需确认实际表\nORDER BY TotalUncleared DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash` 无 `UnderdueCheque` / `NextDayDueCheque` 字段,需业务确认支票数据存储位置", "question_en": "What is the total amount of uncleared cheques received today?", "rating": 4, "execution_result": null, "result_note": "当前查询无未清算支票", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q19", "question_zh": "列出今日起保证金比例发生变动的所有证券。", "sql": "-- 查询保证金比例变动的证券 (固定日期: 2026-04-02)\nSELECT \n i.InstrumentID,\n i.Name AS InstrumentName,\n i.MarginPercentage AS CurrentMarginRatio,\n i.MarginChangeDate\nFROM MCInstrument i\nWHERE i.MarginChangeDate = '2026-04-02'\nORDER BY i.MarginPercentage DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "i", "columns": []}}, "joins": []}, "explanation": "- `MCInstrument.MarginPercentage` 当前保证金比例\n- `MarginChangeDate` 变动日期", "question_en": "List all instruments with margin ratio changes effective today.", "rating": 7, "execution_result": null, "result_note": "当前查询无保证金比例变动记录", "tags": ["margin", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q22", "question_zh": "列出今日所有公司账户与客户账户之间的现金划转。", "sql": "-- 查询公司账户与客户账户现金划转 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n a.AccountType,\n c.CurrencyID,\n c.TodayIn AS CashInflow,\n c.TodayOut AS CashOutflow,\n c.Settled AS CurrentBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE (c.TodayIn > 0 OR c.TodayOut > 0)\nORDER BY c.TodayIn + c.TodayOut DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- 公司账户与客户账户通过 `AccountType` 区分\n- `TodayIn/TodayOut` 记录现金流动", "question_en": "List all cash movements between house and client accounts today.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q23", "question_zh": "列出所有逾期未付保证金利息的账户。", "sql": "-- 查询逾期保证金利息账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.LoanInterestMarginOverdue AS MarginOverdueInterest,\n c.LoanInterestMarginBOverdue AS MarginBOverdueInterest,\n c.LoanInterestOverdue AS GeneralOverdueInterest\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.LoanInterestMarginOverdue > 0 \n OR c.LoanInterestMarginBOverdue > 0\n OR c.LoanInterestOverdue > 0\nORDER BY (c.LoanInterestMarginOverdue + c.LoanInterestMarginBOverdue + c.LoanInterestOverdue) DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `LoanInterestMarginOverdue` 保证金账户逾期利息\n- `LoanInterestMarginBOverdue` B类保证金逾期利息", "question_en": "Show all accounts with overdue margin interest payments.", "rating": 8, "execution_result": null, "result_note": "当前查询无逾期利息记录", "tags": ["join", "ordering", "margin", "filter", "account", "interest"], "difficulty": "hard"}
{"qid": "Q24", "question_zh": "有多少客户报表已生成成功但尚未发送?", "sql": "-- 查询已生成但未发送的报表\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n a.LastDailyStatementDate,\n a.LastMonthlyStatementDate,\n a.LastStatementGenerateTime,\n a.LastStatementSendTime,\n CASE \n WHEN a.LastStatementGenerateTime > a.LastStatementSendTime THEN '未发送'\n ELSE '已发送'\n END AS DeliveryStatus\nFROM MCAccount a\nWHERE a.LastStatementGenerateTime IS NOT NULL\n AND (a.LastStatementSendTime IS NULL \n OR a.LastStatementGenerateTime > a.LastStatementSendTime)\nORDER BY a.LastStatementGenerateTime DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `LastStatementGenerateTime` 报表生成时间\n- `LastStatementSendTime` 报表发送时间", "question_en": "How many client statements were successfully generated but not yet delivered?", "rating": 7, "execution_result": null, "result_note": "当前查询无未发送报表", "tags": ["ordering", "account", "filter", "statement"], "difficulty": "easy"}
{"qid": "Q25", "question_zh": "列出所有待批准的股票转移请求。", "sql": "-- 查询待批准的股票转移\nSELECT \n AccountID,\n InstrumentID,\n MovementType,\n MovementQuantity,\n FromAccountID,\n ToAccountID,\n RequestDate,\n ApprovalStatus,\n RequestedBy\nFROM BCAccountInstrumentMovement\nWHERE ApprovalStatus = 'P'\nORDER BY RequestDate DESC;", "schema_info": {"tables": {"BCAccountInstrumentMovement": {"alias": "BCAccountInstrumentMovement", "columns": []}}, "joins": []}, "explanation": "- 股票转移请求存储在专用表中\n- `ApprovalStatus = 'P'` 待批准状态", "question_en": "Show all pending stock movement requests that require approval.", "rating": 6, "execution_result": null, "result_note": "当前查询无待批准请求", "tags": ["filter", "ordering"], "difficulty": "easy"}
{"qid": "Q26", "question_zh": "本月各交易所的结算费用明细如何?", "sql": "-- 按交易所统计结算费用 (2026年4月)\n-- 说明:BCAccountInstrument 表中 TotalBoughtFee/TotalSoldFee 是持仓级别的交易费用字段\n-- LastTransactionDate 表示该持仓最后交易日期\n-- 查询逻辑:筛选最后交易日期在本月内的持仓记录,按交易所汇总交易费用\nSELECT \n bi.MarketID,\n m.MarketName,\n SUM(bi.TotalBoughtFee) AS TotalBuyFee,\n SUM(bi.TotalSoldFee) AS TotalSellFee,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalSettlementFee,\n COUNT(DISTINCT bi.AccountID) AS TradingAccountCount\nFROM BCAccountInstrument bi\nINNER JOIN MCMarket m ON bi.MarketID = m.MarketID\nWHERE bi.LastTransactionDate >= '2026-04-01' AND bi.LastTransactionDate < '2026-05-01'\nGROUP BY bi.MarketID, m.MarketName\nORDER BY TotalSettlementFee DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCMarket": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.MarketID = m.MarketID"}]}, "explanation": "- `BCAccountInstrument` 存储持仓级别信息,包含各持仓的交易费用累计\n- `MCMarket` 存储市场信息,提供市场名称\n- `LastTransactionDate` 用于过滤本月有交易的持仓记录\n- 按市场分组汇总结算费用", "question_en": "What is the breakdown of settlement fees by exchange for this month?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "trade", "aggregation", "date_range"], "difficulty": "hard"}
{"qid": "Q27", "question_zh": "列出所有超过3天的暂记账户分录。", "sql": "-- 查询超过3天的暂记账户分录 (2026-04-02)\n-- 说明:TCAccountCashMovement 是现金流水表\n-- NeedHoldFlag='Y' 表示暂记分录\n-- Amount - ReleasedAmount 表示未释放金额(暂记余额)\n-- 筛选未释放且超过3天的暂记分录\nSELECT \n cm.AccountID,\n cm.MovementID,\n cm.ValueDate,\n cm.CurrencyID,\n cm.Amount - ISNULL(cm.ReleasedAmount, 0) AS PendingBalance,\n cm.Remark,\n DATEDIFF(DAY, cm.ValueDate, '2026-04-02') AS DaysOutstanding\nFROM TCAccountCashMovement cm\nWHERE cm.NeedHoldFlag = 'Y'\n AND cm.Amount - ISNULL(cm.ReleasedAmount, 0) != 0\n AND DATEDIFF(DAY, cm.ValueDate, '2026-04-02') > 3\nORDER BY DaysOutstanding DESC, PendingBalance DESC;", "schema_info": {"tables": {"TCAccountCashMovement": {"alias": "cm", "columns": []}}, "joins": []}, "explanation": "- `TCAccountCashMovement` 存储现金流水记录\n- `NeedHoldFlag = 'Y'` 标识暂记(待确认)分录\n- `Amount - ReleasedAmount` 计算未释放的暂记余额\n- `DATEDIFF` 计算距今天数\n- `DATEDIFF > 3` 筛选超过3天的记录", "question_en": "List all suspense account entries older than 3 days.", "rating": 9, "execution_result": null, "result_note": "**查询结果:0条记录**\n\n当前没有超过3天未释放的暂记账户分录。所有暂记分录的 ReleasedAmount = Amount,已全部释放。", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q28", "question_zh": "哪些客户已请求更改结算货币?", "sql": "-- 查询请求更改结算货币的客户\n-- 说明:经查 MCAccountCurrency 表无 CurrencyChangeStatus/RequestedCurrencyID 等字段\n-- 数据库中没有专门的货币变更请求表\n-- 此查询基于账户货币历史时间表(HCAccountCurrencyTimetable)展示货币生效安排\nSELECT \n act.AccountID,\n mca.Name AS AccountName,\n act.CurrencyID AS Currency,\n act.EffectiveDateFrom,\n act.EffectiveDateTo,\n act.AccountTypeID\nFROM HCAccountCurrencyTimetable act\nINNER JOIN MCAccount mca ON act.AccountID = mca.AccountID\nWHERE act.EffectiveDateTo IS NULL\nORDER BY act.EffectiveDateFrom DESC;", "schema_info": {"tables": {"HCAccountCurrencyTimetable": {"alias": "act", "columns": []}, "MCAccount": {"alias": "mca", "columns": []}}, "joins": [{"type": "INNER", "on": "act.AccountID = mca.AccountID"}]}, "explanation": "- `HCAccountCurrencyTimetable` 记录账户货币生效时间表\n- `EffectiveDateTo IS NULL` 表示当前生效的货币配置\n- 如需货币变更请求功能,建议在系统中扩展相关表结构", "question_en": "Which clients have requested a change in settlement currency?", "rating": 4, "execution_result": null, "result_note": "**说明:** 数据库中没有专门的货币变更请求表。`MCAccountCurrency` 表仅记录账户当前货币配置,无变更请求字段。", "tags": ["join", "account", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q29", "question_zh": "列出后台系统中所有活跃用户账户及其最后登录日期。", "sql": "-- 查询活跃用户及其登录情况\nSELECT \n u.UserID,\n u.Name AS UserName,\n u.Status,\n u.LogonEnableFlag,\n u.LastLogonTime,\n u.BranchID,\n CASE u.CompanyAEFlag WHEN 'Y' THEN '公司经纪' ELSE '个人' END AS AEType,\n CASE \n WHEN u.LastLogonTime >= DATEADD(DAY, -7, GETDATE()) THEN '近7天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -30, GETDATE()) THEN '近30天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -90, GETDATE()) THEN '近90天活跃'\n ELSE '长期未登录'\n END AS ActivityStatus\nFROM MCUser u\nWHERE u.State = 'A'\n AND u.LogonEnableFlag = 'Y'\nORDER BY u.LastLogonTime DESC;", "schema_info": {"tables": {"MCUser": {"alias": "u", "columns": []}}, "joins": []}, "explanation": "- `MCUser` 存储用户信息\n- `LastLogonTime` 最后登录时间", "question_en": "List all active user accounts in the back office system with last login date.", "rating": 9, "execution_result": null, "result_note": "| UserID | UserName | Status | LogonEnableFlag | LastLogonTime | ActivityStatus |\n|--------|----------|--------|-----------------|---------------|----------------|\n| SUPPORT | SUPPORT | N | Y | 2026-04-08 | 近7天活跃 |\n| ROSANNA | ROSANNA | N | Y | 2025-10-21 | 长期未登录 |\n| SING | WONG LO SING | N | Y | 2025-10-21 | 长期未登录 |\n| LEONNG | LEON NG | N | Y | 2025-10-21 | 长期未登录 |", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q30", "question_zh": "按结算日期划分的未结算交易总风险敞口是多少?", "sql": "-- 按结算日期分组的未结算交易敞口\nSELECT \n SettlementType,\n SUM(Amount) AS TotalExposure\nFROM (\n SELECT 'DueBuy_T1' AS SettlementType, SUM(DueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'DueSell_T1' AS SettlementType, SUM(DueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueBuy' AS SettlementType, SUM(NextDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueSell' AS SettlementType, SUM(NextDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueBuy' AS SettlementType, SUM(NextTwoDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueSell' AS SettlementType, SUM(NextTwoDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueBuy' AS SettlementType, SUM(TodayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueSell' AS SettlementType, SUM(TodayDueSell) AS Amount FROM BCAccountInstrument\n) t\nGROUP BY SettlementType\nORDER BY SettlementType;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表包含所有账户的证券持仓和交收信息\n- `DueBuy/DueSell` 表示T+1到期的买卖数量", "question_en": "What is the total exposure from unsettled trades by settlement date?", "rating": 8, "execution_result": null, "result_note": "| SettlementType | TotalExposure |\n|----------------|---------------|\n| DueBuy_T1 | 0 |\n| DueSell_T1 | 0 |\n| NextDayDueBuy | 0 |\n| NextDayDueSell | 0 |\n| NextTwoDayDueBuy | 0 |\n| NextTwoDayDueSell | 0 |\n| TodayDueBuy | 1,800 |\n| TodayDueSell | 1,000 |\n\n**注:** `DueBuy/DueSell` 等字段表示应交收数量(T+1/T+2/今日),非金额敞口。如需金额敞口,需乘以价格。", "tags": ["union", "trade", "ordering", "aggregation"], "difficulty": "hard"}
{"qid": "Q32", "question_zh": "各市场客户不同资产(如股票、债券、基金、虚拟资产)的总持仓是多少?", "sql": "-- 按市场统计客户持仓\nSELECT \n b.MarketID,\n COUNT(DISTINCT b.AccountID) AS AccountCount,\n SUM(b.Settled) AS TotalQuantity,\n SUM(b.CostAmount) AS TotalCostAmount,\n SUM(b.TotalBoughtQuantity) AS TotalBoughtQty,\n SUM(b.TotalSoldQuantity) AS TotalSoldQty\nFROM BCAccountInstrument b\nGROUP BY b.MarketID\nORDER BY TotalCostAmount DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "b", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表记录账户在各市场的持仓\n- `MarketID` 区分不同市场", "question_en": "What is the total client holding of different assets (e.g., stocks, bonds, funds, virtual assets) by each market?", "rating": 8, "execution_result": null, "result_note": "| MarketID | AccountCount | TotalQuantity | TotalCostAmount | TotalBoughtQty | TotalSoldQty |\n|----------|-------------|---------------|-----------------|---------------|-------------|\n| HKEX | 2,102 | 717,471,548 | 87,813,213.45 | 1,015,923,906 | 298,452,798 |\n| SETW | 2 | 3,100 | 32,298.50 | 4,100 | 1,000 |", "tags": ["account", "holding", "ordering", "aggregation"], "difficulty": "medium"}
{"qid": "Q34", "question_zh": "保证金账户前20大持仓(按市值)是多少?", "sql": "-- 保证金账户按市值排序的前20持仓\nSELECT TOP 20\n a.AccountID,\n a.Name AS AccountName,\n a.MarketValue,\n a.MarginDebitRatio AS MarginDebitBalanceRatio,\n a.MarginPosition,\n a.CallForDeposit,\n a.MarginFacilityFlag\nFROM MCAccount a\nWHERE a.MarginFacilityFlag = 'Y'\n AND a.State = 'A'\n AND a.MarketValue > 0\nORDER BY a.MarketValue DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 表包含所有账户信息\n- `MarginFacilityFlag = 'Y'` 筛选保证金账户", "question_en": "What are the top 20 holdings (based on market value) for margin accounts?", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginPosition |\n|-----------|-------------|------------|----------------|\n| M050009 | NG SUN SHU*** | 57,420,000 | 35,515,021.58 |\n| M050013 | NG CHUNG WAI*** | 19,504,520 | 10,918,958.78 |\n| M050193 | WONG KING YIU*** ^ | 11,682,920 | 3,340,099.05 |\n| P020160 | LAW SHIU MING DENNIS | 7,520,370 | 0 |\n| P030078 | MAK SUI BING | 7,120,309.94 | 0 |\n| P051101 | CHUNG CHUNG YEE | 7,117,808.04 | 0 |\n| M050170 | FUNG LAI FONG ANNA | 7,009,227.25 | 4,136,857 |\n| P220005 | LAI KAM SUI # | 5,837,102.10 | 97.97 |\n| P280628 | CHAN KWOK MO # | 5,761,997.48 | 62,508.23 |\n| P280455 | LEUNG KA CHI # | 5,487,971.20 | -64,981.22 |\n\n(共20条记录,以上展示前10条)", "tags": ["ordering", "holding", "margin", "filter", "limit", "account"], "difficulty": "hard"}
{"qid": "Q35", "question_zh": "列出本月按客户主任分组的佣金总额,以及相应的成交金额和返佣金额。", "sql": "-- 按经纪商/客户主任分组的佣金统计\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee) AS TotalBuyCommission,\n SUM(bi.TotalSoldFee) AS TotalSellCommission,\n SUM(bi.TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(bi.TotalSoldConsideration) AS TotalSellConsideration,\n SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE a.State = 'A'\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCAccount.AEID` 关联经纪商/客户主任\n- `BCAccountInstrument` 包含交易费用数据", "question_en": "List the total commission received this month by AE, along with corresponding consideration and rebate amounts.", "rating": 8, "execution_result": null, "result_note": "| AEID | AEName | AccountCount | TotalBuyCommission | TotalSellCommission | TotalCommission |\n|------|--------|-------------|-------------------|--------------------|----------------|\n| C01 | CHAN YUET HUNG | 628 | 183,244.64 | 187,220.59 | 370,465.23 |\n| C28 | CHAN SHU SHAN | 405 | 179,275.89 | 176,760.39 | 356,036.28 |\n| C05 | CENTRAL | 517 | 97,368.51 | 102,819.88 | 200,188.39 |\n| C33 | LEON NG | 13 | 71,541.06 | 72,620.60 | 144,161.66 |\n| C07 | CHAN WING PAI | 75 | 73,255.68 | 69,115.58 | 142,371.26 |\n| C10 | TOKWAWAN / KOWLOON CITY | 369 | 51,059.78 | 57,288.86 | 108,348.64 |\n| C08 | WONG HON KONG | 380 | 47,505.15 | 46,300.39 | 93,805.54 |\n| C36 | Name Of C36 | 146 | 40,945.66 | 35,682.86 | 76,628.52 |\n| C66 | CHEUNG YUK LING IVA | 17 | 24,458.82 | 22,723.18 | 47,182.00 |\n| C19 | WONG LO SING | 60 | 13,337.69 | 13,912.30 | 27,249.99 |\n\n(共15个AE有佣金记录,以上展示前10条)\n\n**注:** 当前SQL无日期条件,统计所有历史累计佣金。如需\"本月\"佣金,需添加 `LastTransactionDate >= '2026-04-01'` 条件。", "tags": ["join", "ordering", "filter", "account", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q37", "question_zh": "是否有正在进行的IPO事件,其认购状态如何?", "sql": "-- 查询进行中的IPO (2026年4月)\nSELECT \n i.InstrumentID,\n i.MarketID,\n i.Name AS InstrumentName,\n i.State AS InstrumentStatus,\n ip.Quantity AS SubscriptionLot,\n ip.SubscriptionAmount,\n ip.CreatedOn AS SubscriptionDate\nFROM MCInstrument i\nINNER JOIN MCInstrumentIPODetail ip ON i.InstrumentID = ip.InstrumentID\nWHERE YEAR(ip.CreatedOn) = 2026\n AND MONTH(ip.CreatedOn) = 4\nORDER BY ip.CreatedOn DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "i", "columns": []}, "MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": [{"type": "INNER", "on": "i.InstrumentID = ip.InstrumentID"}]}, "explanation": "- `MCInstrument` 表记录证券信息\n- `MCInstrumentIPODetail` 记录IPO认购详情", "question_en": "Are there any IPO events currently in progress, and what is their subscription status?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "filter", "ipo", "ordering"], "difficulty": "easy"}
{"qid": "Q42", "question_zh": "列出后台系统中的活跃用户。", "sql": "-- 查询后台系统活跃用户\nSELECT \n u.UserID,\n u.Name AS UserName,\n u.Status,\n u.LogonEnableFlag,\n u.LastLogonTime,\n u.BranchID,\n u.DepartmentID,\n CASE u.CompanyAEFlag WHEN 'Y' THEN '公司经纪' ELSE '个人' END AS AEType\nFROM MCUser u\nWHERE u.State = 'A'\n AND u.LogonEnableFlag = 'Y'\nORDER BY u.LastLogonTime DESC;", "schema_info": {"tables": {"MCUser": {"alias": "u", "columns": []}}, "joins": []}, "explanation": "- `MCUser` 存储系统用户信息\n- `State = 'A'` 用户状态正常", "question_en": "List active users in the back office.", "rating": 9, "execution_result": null, "result_note": "| UserID | UserName | Status | LogonEnableFlag | LastLogonTime | AEType |\n|--------|----------|--------|-----------------|---------------|--------|\n| SUPPORT | SUPPORT | N | Y | 2026-04-03 18:53:04 | 个人 |\n| ROSANNA | ROSANNA | N | Y | 2025-10-21 16:47:11 | 个人 |", "tags": ["filter", "ordering"], "difficulty": "easy"}
{"qid": "Q43", "question_zh": "列出持仓为负数(透支)的账户。", "sql": "-- 查询透支持仓账户\nSELECT \n AccountID,\n Name AS AccountName,\n MarketValue,\n AssetBalance,\n LiabilityBalance,\n MarginPosition,\n MarginFacilityFlag\nFROM MCAccount\nWHERE MarketValue < 0\n AND State = 'A'\nORDER BY MarketValue ASC;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MarketValue < 0` 筛选持仓为负的账户\n- 持仓为负通常表示账户存在透支或结算问题", "question_en": "List accounts with overdrawn positions.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginFacilityFlag |\n|-----------|-------------|-------------|-------------------|\n| P030012 | LAI YEE TAK HELEN | -112,196.60 | N |\n| P350022 | CHAN YAU KING*** | -92,950.00 | N |\n| P011212 | NG SIU PING | -12,352.00 | N |", "tags": ["account", "holding", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q45", "question_zh": "不同经纪商(如非中央结算系统持仓)的客户总持仓是多少?", "sql": "-- 按托管位置统计持仓(非CCASS)\nSELECT \n loc.LocationID,\n loc.Name AS LocationName,\n COUNT(DISTINCT bi.AccountID) AS AccountCount,\n SUM(bi.Settled) AS TotalQuantity,\n SUM(bi.CostAmount) AS TotalCostAmount\nFROM BCAccountLocationInstrument bi\nINNER JOIN MCLocation loc ON bi.LocationID = loc.LocationID\nWHERE loc.CCASSFlag = 'N'\nGROUP BY loc.LocationID, loc.Name\nORDER BY TotalQuantity DESC;", "schema_info": {"tables": {"BCAccountLocationInstrument": {"alias": "bi", "columns": []}, "MCLocation": {"alias": "loc", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.LocationID = loc.LocationID"}]}, "explanation": "- `BCAccountLocationInstrument` 记录按托管位置分类的持仓\n- `MCLocation` 存储托管位置信息", "question_en": "What is the total client holding at different broker firms (e.g., non-CCASS locations)?", "rating": 7, "execution_result": null, "result_note": "当前查询需要验证 Location 表关联", "tags": ["join", "ordering", "holding", "broker", "filter", "account", "aggregation"], "difficulty": "hard"}
{"qid": "Q46", "question_zh": "支付给其他经纪商的佣金是多少?", "sql": "-- 查询支付给其他经纪商的佣金\nSELECT \n b.BrokerID,\n b.Name AS BrokerName,\n SUM(bc.Commission) AS TotalCommission,\n SUM(bc.Consideration) AS TotalConsideration\nFROM MCBroker b\nINNER JOIN BCBrokerCash bc ON b.BrokerID = bc.BrokerID\nWHERE bc.Commission > 0\nGROUP BY b.BrokerID, b.Name\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCBroker": {"alias": "b", "columns": []}, "BCBrokerCash": {"alias": "bc", "columns": []}}, "joins": [{"type": "INNER", "on": "b.BrokerID = bc.BrokerID"}]}, "explanation": "- `MCBroker` 存储经纪商信息\n- `BCBrokerCash` 可能包含经纪商现金和佣金数据", "question_en": "How much commission has been paid to other brokers?", "rating": 6, "execution_result": null, "result_note": "当前查询需要验证经纪商佣金表关联", "tags": ["join", "ordering", "broker", "filter", "aggregation"], "difficulty": "hard"}
{"qid": "Q48", "question_zh": "列出所有支持保证金的证券及其相应的保证金比例。", "sql": "-- 查询支持保证金的证券\nSELECT \n InstrumentID,\n Name AS InstrumentName,\n MarginPercentage AS MarginRatio,\n CASE \n WHEN MarginPercentage >= 0.7 THEN '高'\n WHEN MarginPercentage >= 0.5 THEN '中'\n WHEN MarginPercentage > 0 THEN '低'\n ELSE 'N/A'\n END AS RiskLevel,\n MarginLimitPerInstrument,\n CollateralRatio\nFROM MCInstrument\nWHERE MarginPercentage IS NOT NULL\n AND MarginPercentage > 0\n AND State = 'A'\nORDER BY MarginPercentage DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "MCInstrument", "columns": []}}, "joins": []}, "explanation": "- `MCInstrument` 存储证券信息\n- `MarginPercentage` 保证金比例", "question_en": "List all instruments that support margin and their corresponding margin ratios.", "rating": 9, "execution_result": null, "result_note": "| InstrumentID | InstrumentName | MarginRatio | RiskLevel |\n|-------------|----------------|-------------|-----------|\n| 00001 | CKH HOLDINGS(S) | 0.70 | 高 |\n| 00002 | CLP HOLDINGS(S) | 0.70 | 高 |\n| 00003 | HK & CHINA GAS(S) | 0.70 | 高 |\n\n(共767条记录)", "tags": ["margin", "limit", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q50", "question_zh": "", "sql": "SELECT TOP\n\t15 c.ContractID,\n\tc.TradeDate,\n\tLTRIM( RTRIM( c.AccountID ) ) AS AccountID,\n\tLTRIM( RTRIM( c.MarketID ) ) AS MarketID,\n\tc.InstrumentID,\n\tc.BuySell,\n\tc.Quantity,\n\tc.Consideration,\n\tLTRIM( RTRIM( c.CurrencyID ) ) AS CurrencyID \nFROM\n\tdbo.TSBAccountContract c\n\tINNER JOIN dbo.MCAccount a ON c.AccountID = a.AccountID \nWHERE\n\tCAST ( c.TradeDate AS DATE ) = '2026-04-02' \n\tAND LTRIM( RTRIM( a.HouseAccountFlag ) ) = 'N' \nORDER BY\n\tc.ContractID;", "schema_info": {"tables": {"TSBAccountContract": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "", "question_en": "列出今天所有客戶的交易記錄", "rating": null, "execution_result": null, "result_note": "| ContractID | TradeDate | AccountID | MarketID | InstrumentID | BuySell | Quantity | Consideration | CurrencyID |\n| :--------- | :--------- | :-------- | :------- | :----------- | :------ | :------- | :------------ | :--------- |\n| B02403846 | 2026-04-02 | P011206 | HKEX | 01810 | B | 600 | 18360 | HKD |\n| B02403847 | 2026-04-02 | P011202 | HKEX | 01810 | B | 200 | 6120 | HKD |\n\n\n\n\n\n---\n\n## 附录:关键表说明\n\n| 表名 | 说明 | 关键字段 |\n|------|------|---------|\n| MCAccount | 账户主表 | AccountID, Name, MarketValue, MarginFacilityFlag |\n| MCUser | 用户表 | UserID, Name, Status, LogonEnableFlag |\n| BCAccountInstrument | 账户持仓 | AccountID, MarketID, Settled, DueBuy, DueSell |\n| BCAccountCash | 账户现金 | AccountID, TodayIn, TodayOut, AccruedInterest |\n| HCAccountMarginCallForDeposit | 追缴保证金 | AccountID, CallForDeposit, CallForDepositDate |\n| MCInstrument | 证券表 | InstrumentID, Name, MarginPercentage |\n| MCInstrumentIPODetail | IPO详情 | InstrumentID, Quantity, SubscriptionAmount |\n| MSBEntitlement | 权益分派 | EntitlementID, BalanceDate, BalanceExDate |\n| MCBroker | 经纪商 | BrokerID, Name |\n| MCLocation | 托管位置 | LocationID, Name, CCASSFlag |\n| HCExchangeRate | 汇率 | ExchangeRateID, ValueDate |\n| HCAccountCashRecord | 现金记录 | AccountID, ValueDate, LedgerBalance |\n\n---\n\n**文档结束**", "tags": ["join", "limit", "filter", "ordering"], "difficulty": "easy"}
+1
View File
@@ -0,0 +1 @@
{"qid": "Q24", "question_zh": "有多少客户报表已生成成功但尚未发送?", "sql": "-- 查询已生成但未发送的报表\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n a.LastDailyStatementDate,\n a.LastMonthlyStatementDate,\n a.LastStatementGenerateTime,\n a.LastStatementSendTime,\n CASE \n WHEN a.LastStatementGenerateTime > a.LastStatementSendTime THEN '未发送'\n ELSE '已发送'\n END AS DeliveryStatus\nFROM MCAccount a\nWHERE a.LastStatementGenerateTime IS NOT NULL\n AND (a.LastStatementSendTime IS NULL \n OR a.LastStatementGenerateTime > a.LastStatementSendTime)\nORDER BY a.LastStatementGenerateTime DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `LastStatementGenerateTime` 报表生成时间\n- `LastStatementSendTime` 报表发送时间", "question_en": "How many client statements were successfully generated but not yet delivered?", "rating": 7, "execution_result": null, "result_note": "当前查询无未发送报表", "tags": ["ordering", "account", "filter", "statement"], "difficulty": "easy"}
+6
View File
@@ -0,0 +1,6 @@
{"qid": "Q1", "question_zh": "按对手方列出截至[日期]的所有未结算交易。", "sql": "-- 按对手方统计截至 2026-04-02 的未结算交易\n-- 使用 TSBBrokerContract(经纪商合约表),按 BrokerID(对手方经纪商)分组\n-- SettleStatus='U' 表示未结算;CashSettleDate <= '2026-04-02' 筛选截至日\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n COUNT(*) AS UnsettledTradeCount,\n SUM(b.SettleQuantity) AS TotalUnsettledQty,\n SUM(b.SettleAmount) AS TotalUnsettledAmount,\n MIN(b.BuySell) + '~' + MAX(b.BuySell) AS BuySellRange,\n MIN(b.CashSettleDate) AS EarliestSettleDate,\n MAX(b.CashSettleDate) AS LatestSettleDate\nFROM TSBBrokerContract b\nLEFT JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.SettleStatus = 'U'\n AND b.CashSettleDate <= '2026-04-02'\nGROUP BY b.BrokerID, m.Name\nORDER BY TotalUnsettledAmount DESC;", "schema_info": {"tables": {"TSBBrokerContract": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "LEFT", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `TSBBrokerContract` 是经纪商/对手方合约表,记录与外部对手方的交易合约,`BrokerID` 即对手方标识\n- `SettleStatus = 'U'` 表示未结算;`CashSettleDate <= '2026-04-02'` 筛选截至日未结清的合约\n- 关联 `MCBroker` 获取对手方经纪商名称\n- 按 `BrokerID` 分组汇总未结算数量和金额", "question_en": "Show all unsettled trades as of [date] grouped by counterparty.", "rating": 9, "execution_result": null, "result_note": "| BrokerID | BrokerName | UnsettledTradeCount | TotalUnsettledQty | TotalUnsettledAmount | BuySellRange | EarliestSettleDate | LatestSettleDate |\n|----------|-----------|---------------------|-------------------|---------------------|--------------|---------------------|-------------------|\n| CCASS | CCASS | 622 | 40,459,253 | 44,173,571.06 | B~S | 2025-07-30 | 2026-04-02 |\n\n> **注**:CCASS(Hong Kong Securities Clearing Company Limited)是香港交易所的中央结算机构,作为交易所交易的核心对手方。622笔未结算合约均为 HKEX 市场。", "tags": ["join", "ordering", "broker", "filter", "trade", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q13", "question_zh": "列出今日到期的所有股票借贷交易。", "sql": "-- 查询今日到期的股票借贷 (参考日期: 2026-04-02)\n-- MCMarket 表仅包含 HKEX/OSL/SETW,无独立借贷市场标识\n-- 股票借贷可能在持仓变动类型 HoldType 中标识,或在专门的 StockBorrowing 表中\n-- 此 SQL 按 DueBuy/DueSell 显示当前待交收证券,作为借贷合约的近似替代\nSELECT \n bi.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.DueBuy AS BorrowQuantity,\n bi.DueSell AS LoanQuantity,\n bi.DueBuy - bi.DueSell AS NetBorrow\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nWHERE bi.DueBuy > 0 OR bi.DueSell > 0;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}]}, "explanation": "- `DueBuy/DueSell` 表示待交收数量(借款买入/借出卖出),反映股票借贷待到期情况\n- `MCMarket` 表无 `MarketType='BORROW'` 标识,现有市场仅为 HKEX/OSL/SETW\n- 股票借贷详情可能存储在 `TSBAccountLoanContract` 或其他借贷专用表中,需业务确认", "question_en": "List all stock borrow/loan transactions due to settle today.", "rating": 5, "execution_result": null, "result_note": "当前查询无结果(BCAccountInstrument 中 DueBuy/DueSell 均为 0,无待交收证券)", "tags": ["join", "trade", "filter"], "difficulty": "medium"}
{"qid": "Q16", "question_zh": "列出T+2交易缺少结算指令的账户。", "sql": "-- 查询T+2待交收但缺少指令的账户\n-- 注意:BCAccountInstrumentInstruction 表不存在,需改用 TSBSettlementInstruction\nSELECT \n bi.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.NextDayDueBuy AS T2DueBuy,\n bi.NextDayDueSell AS T2DueSell\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nWHERE (bi.NextDayDueBuy > 0 OR bi.NextDayDueSell > 0)\n AND NOT EXISTS (\n SELECT 1 FROM TSBSettlementInstruction si\n WHERE si.AccountOrBrokerID = bi.AccountID\n AND si.InstrumentID = bi.InstrumentID\n AND si.State IN ('P','A')\n );", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}, "TSBSettlementInstruction": {"alias": "si", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}]}, "explanation": "- `NextDayDueBuy/NextDayDueSell` T+2交收数量(次日到期)\n- `TSBSettlementInstruction` 是结算指令表,通过 `NOT EXISTS` 排除已有指令的记录\n- `BCAccountInstrumentInstruction` 表不存在,不能使用", "question_en": "Show accounts where settlement instruction is missing for T+2 trades.", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "trade"], "difficulty": "medium"}
{"qid": "Q26", "question_zh": "本月各交易所的结算费用明细如何?", "sql": "-- 按交易所统计结算费用 (2026年4月)\n-- 说明:BCAccountInstrument 表中 TotalBoughtFee/TotalSoldFee 是持仓级别的交易费用字段\n-- LastTransactionDate 表示该持仓最后交易日期\n-- 查询逻辑:筛选最后交易日期在本月内的持仓记录,按交易所汇总交易费用\nSELECT \n bi.MarketID,\n m.MarketName,\n SUM(bi.TotalBoughtFee) AS TotalBuyFee,\n SUM(bi.TotalSoldFee) AS TotalSellFee,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalSettlementFee,\n COUNT(DISTINCT bi.AccountID) AS TradingAccountCount\nFROM BCAccountInstrument bi\nINNER JOIN MCMarket m ON bi.MarketID = m.MarketID\nWHERE bi.LastTransactionDate >= '2026-04-01' AND bi.LastTransactionDate < '2026-05-01'\nGROUP BY bi.MarketID, m.MarketName\nORDER BY TotalSettlementFee DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCMarket": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.MarketID = m.MarketID"}]}, "explanation": "- `BCAccountInstrument` 存储持仓级别信息,包含各持仓的交易费用累计\n- `MCMarket` 存储市场信息,提供市场名称\n- `LastTransactionDate` 用于过滤本月有交易的持仓记录\n- 按市场分组汇总结算费用", "question_en": "What is the breakdown of settlement fees by exchange for this month?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "trade", "aggregation", "date_range"], "difficulty": "hard"}
{"qid": "Q30", "question_zh": "按结算日期划分的未结算交易总风险敞口是多少?", "sql": "-- 按结算日期分组的未结算交易敞口\nSELECT \n SettlementType,\n SUM(Amount) AS TotalExposure\nFROM (\n SELECT 'DueBuy_T1' AS SettlementType, SUM(DueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'DueSell_T1' AS SettlementType, SUM(DueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueBuy' AS SettlementType, SUM(NextDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueSell' AS SettlementType, SUM(NextDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueBuy' AS SettlementType, SUM(NextTwoDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueSell' AS SettlementType, SUM(NextTwoDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueBuy' AS SettlementType, SUM(TodayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueSell' AS SettlementType, SUM(TodayDueSell) AS Amount FROM BCAccountInstrument\n) t\nGROUP BY SettlementType\nORDER BY SettlementType;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表包含所有账户的证券持仓和交收信息\n- `DueBuy/DueSell` 表示T+1到期的买卖数量", "question_en": "What is the total exposure from unsettled trades by settlement date?", "rating": 8, "execution_result": null, "result_note": "| SettlementType | TotalExposure |\n|----------------|---------------|\n| DueBuy_T1 | 0 |\n| DueSell_T1 | 0 |\n| NextDayDueBuy | 0 |\n| NextDayDueSell | 0 |\n| NextTwoDayDueBuy | 0 |\n| NextTwoDayDueSell | 0 |\n| TodayDueBuy | 1,800 |\n| TodayDueSell | 1,000 |\n\n**注:** `DueBuy/DueSell` 等字段表示应交收数量(T+1/T+2/今日),非金额敞口。如需金额敞口,需乘以价格。", "tags": ["union", "trade", "ordering", "aggregation"], "difficulty": "hard"}
{"qid": "Q31", "question_zh": "指定日期或日期范围内收到的交易量(如成交金额)及相应佣金是多少?", "sql": "-- 交易量和佣金统计\nSELECT \n SUM(TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(TotalBoughtFee) AS TotalBuyCommission,\n SUM(TotalSoldConsideration) AS TotalSellConsideration,\n SUM(TotalSoldFee) AS TotalSellCommission,\n SUM(TotalBoughtConsideration) + SUM(TotalSoldConsideration) AS TotalConsideration,\n SUM(TotalBoughtFee) + SUM(TotalSoldFee) AS TotalCommission\nFROM BCAccountInstrument;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表记录了账户所有历史买卖交易\n- `TotalBoughtConsideration / TotalSoldConsideration`: 买卖成交金额", "question_en": "What is the trading volume (e.g., consideration) and corresponding commission amount received for a specific date or date range?", "rating": 9, "execution_result": null, "result_note": "| TotalBuyConsideration | TotalBuyCommission | TotalSellConsideration | TotalSellCommission | TotalConsideration | TotalCommission |\n|---------------------|-------------------|----------------------|--------------------|-------------------|-----------------|\n| 945,480,833.78 | 793,149.07 | 278,693,891.64 | 809,248.89 | 1,224,174,725.42 | 1,602,397.96 |", "tags": ["trade", "aggregation"], "difficulty": "easy"}
+2
View File
@@ -0,0 +1,2 @@
{"qid": "Q30", "question_zh": "按结算日期划分的未结算交易总风险敞口是多少?", "sql": "-- 按结算日期分组的未结算交易敞口\nSELECT \n SettlementType,\n SUM(Amount) AS TotalExposure\nFROM (\n SELECT 'DueBuy_T1' AS SettlementType, SUM(DueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'DueSell_T1' AS SettlementType, SUM(DueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueBuy' AS SettlementType, SUM(NextDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueSell' AS SettlementType, SUM(NextDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueBuy' AS SettlementType, SUM(NextTwoDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueSell' AS SettlementType, SUM(NextTwoDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueBuy' AS SettlementType, SUM(TodayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueSell' AS SettlementType, SUM(TodayDueSell) AS Amount FROM BCAccountInstrument\n) t\nGROUP BY SettlementType\nORDER BY SettlementType;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表包含所有账户的证券持仓和交收信息\n- `DueBuy/DueSell` 表示T+1到期的买卖数量", "question_en": "What is the total exposure from unsettled trades by settlement date?", "rating": 8, "execution_result": null, "result_note": "| SettlementType | TotalExposure |\n|----------------|---------------|\n| DueBuy_T1 | 0 |\n| DueSell_T1 | 0 |\n| NextDayDueBuy | 0 |\n| NextDayDueSell | 0 |\n| NextTwoDayDueBuy | 0 |\n| NextTwoDayDueSell | 0 |\n| TodayDueBuy | 1,800 |\n| TodayDueSell | 1,000 |\n\n**注:** `DueBuy/DueSell` 等字段表示应交收数量(T+1/T+2/今日),非金额敞口。如需金额敞口,需乘以价格。", "tags": ["union", "trade", "ordering", "aggregation"], "difficulty": "hard"}
{"qid": "Q47", "question_zh": "今日/指定日期发放了多少份日结单或月结单?", "sql": "-- 查询报表发放统计 (2026-04-02)\nSELECT \n 'Daily Statement' AS StatementType,\n COUNT(*) AS StatementCount\nFROM MCAccount\nWHERE LastDailyStatementDate = '2026-04-02'\nUNION ALL\nSELECT \n 'Monthly Statement' AS StatementType,\n COUNT(*) AS StatementCount\nFROM MCAccount\nWHERE LastMonthlyStatementDate = '2026-04-02';", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 记录账户报表发送日期\n- `LastDailyStatementDate` 最近日结单发送日期", "question_en": "How many daily or monthly statements were issued today / on a specific date?", "rating": 9, "execution_result": null, "result_note": "", "tags": ["union", "filter", "aggregation"], "difficulty": "hard"}
+29
View File
@@ -0,0 +1,29 @@
{"qid": "Q3", "question_zh": "今日结算使用的汇率是多少?", "sql": "-- 查询汇率类型列表 (固定日期: 2026-04-02)\nSELECT \n ExchangeRateID, \n Name, \n NameEx\nFROM HCExchangeRate\nWHERE ValueDate = '2026-04-02'\nORDER BY ExchangeRateID;", "schema_info": {"tables": {"HCExchangeRate": {"alias": "HCExchangeRate", "columns": []}}, "joins": []}, "explanation": "- `HCExchangeRate` 存储汇率类型定义\n- `HCExchangeRateDetail` 存储各货币对的汇率值\n- 两个表通过 `ExchangeRateID` + `ValueDate` 关联\n- `ExchangeRateDirection` = 'D' 表示直接汇率", "question_en": "What are the currency exchange rates used for today's settlement?", "rating": 9, "execution_result": null, "result_note": "", "tags": ["exchange_rate", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q4", "question_zh": "哪些券商尚有未履行的交收义务?", "sql": "-- 查询有未履行交收义务的经纪商(截至 2026-04-02)\n-- Settled < 0 表示经纪商欠我们的现金(未履行交收义务)\n-- 注意:BCBrokerCash.Settled 是经纪商在我们账户的已结算现金余额,负数=经纪商欠款\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n b.CurrencyID,\n b.Settled AS OwedToUsAmount,\n ABS(b.Settled) AS OutstandingAmount\nFROM BCBrokerCash b\nINNER JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.Settled < 0\nORDER BY ABS(b.Settled) DESC;", "schema_info": {"tables": {"BCBrokerCash": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `BCBrokerCash` 记录经纪商在我们账户的结算现金,`Settled < 0` = 经纪商欠我们(未履行交收义务)\n- 关联 `MCBroker` 获取经纪商名称\n- 按欠款金额降序排列,优先处理大额欠款", "question_en": "Which brokers have outstanding delivery obligations to us?", "rating": 8, "execution_result": null, "result_note": "| BrokerID | BrokerName | CurrencyID | OwedToUsAmount | OutstandingAmount |\n|----------|-----------|------------|-----------------|-------------------|\n| CCASS | CCASS | CNY | -52,680.00 | 52,680.00 |\n| CCASS | CCASS | USD | -90.00 | 90.00 |\n\n> 注:CCASS 欠我们的结算现金(CNY 52,680 + USD 90)。HKD 余额为正(+4,202,811.87)表示我们欠 CCASS,不属于\"未履行交收义务\"范畴。", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q5", "question_zh": "列出今日发出的所有追收保证金通知及其回复状态。", "sql": "-- 查询今日追缴保证金记录 (参考日期: 2026-04-02)\n-- 使用 MCAccount 的账户级追缴字段(CallForDepositDate = 追缴通知发出日期)\n-- 注意:HCAccountMarginCallForDeposit 是追缴每日快照表,不含\"通知发出日\"字段\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n a.CallForDeposit AS CallAmount,\n a.CallForDepositDate AS IssueDate,\n a.CallForDepositDays AS OverdueDays\nFROM MCAccount a\nWHERE a.CallForDepositDate = '2026-04-02'\nORDER BY a.CallForDeposit DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.CallForDepositDate` = 追缴通知发出日期,`CallForDeposit` = 追缴金额\n- `CallForDeposit < 0` 表示已结清;如查活跃追缴,应筛选 `CallForDeposit > 0`\n- `HCAccountMarginCallForDeposit` 是追缴每日历史快照,不适合查询\"今日发出的通知\"\n- `CallStatus` 字段在 `HCAccountMarginCallForDeposit` 中不存在", "question_en": "Show all margin calls issued today and their response status.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果(测试环境中 MCAccount 的 `CallForDepositDate` 最新到 2025-10-31,2026-04-02 无追缴通知记录)\n\n> 注:`MCAccount.CallForDeposit` 当前所有值均为负数(已结清的追缴金额),无活跃追缴记录。", "tags": ["margin", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q8", "question_zh": "明天生效的公司行动涉及哪些证券?", "sql": "-- 查询明日生效的公司行动 (固定日期: 2026-04-03)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.BalanceDate AS EffectiveDate,\n e.BalanceExDate AS ExDate,\n e.Remark AS Description\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE (e.BalanceDate = '2026-04-03' OR e.BalanceExDate = '2026-04-03')\n AND e.State = 'A';", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录权益分派信息\n- `BalanceDate` 权益登记日期\n- `BalanceExDate` 除权日期", "question_en": "Which instruments have corporate actions effective tomorrow?", "rating": 8, "execution_result": null, "result_note": "当前查询无结果(2026-04-03无公司行动)", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q9", "question_zh": "今日预计收到哪些股息?", "sql": "-- 查询今日预计收到的股息 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceDate AS PaymentDate,\n e.BalanceType,\n e.Remark AS DividendDetails\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.BalanceDate = '2026-04-02'\n AND e.BalanceType = 'C'\n AND e.State = 'A'\nORDER BY i.Name;", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录所有权益分派\n- `BalanceType = 'C'` 表示现金股息\n- `BalanceDate` 股息支付日期", "question_en": "What dividends are expected to be received today?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q10", "question_zh": "列出所有进行中IPO的待缴申购金额。", "sql": "-- 查询进行中IPO的待缴金额\nSELECT \n ip.InstrumentID,\n i.Name AS InstrumentName,\n i.State AS InstrumentStatus,\n ip.SubscriptionAmount,\n ip.SubscriptionPrice,\n ip.Quantity AS SubscriptionLot,\n ip.CreatedOn AS SubscriptionDate,\n ip.State AS SubscriptionStatus\nFROM MCInstrumentIPODetail ip\nINNER JOIN MCInstrument i ON ip.InstrumentID = i.InstrumentID\nWHERE ip.State = 'A'\n AND i.State = 'A'\nORDER BY ip.CreatedOn DESC;", "schema_info": {"tables": {"MCInstrumentIPODetail": {"alias": "ip", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "ip.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MCInstrumentIPODetail` 记录IPO认购详情\n- `SubscriptionAmount` 申购金额\n- `State = 'A'` 表示进行中", "question_en": "Show all pending subscription amounts for ongoing IPOs.", "rating": 8, "execution_result": null, "result_note": "| InstrumentID | InstrumentName | SubscriptionAmount | SubscriptionPrice | Quantity |\n|--------------|----------------|-------------------|-------------------|----------|\n| 02259 | HKEX | 7,231.19 | 36.16 | 100 |\n| 02259 | HKEX | 14,462.40 | 36.16 | 200 |\n\n> 注:MCInstrumentIPODetail 共 586 条进行中 IPO 记录(State='A'),以上为示例行。", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q14", "question_zh": "列出已申请但尚未处理的客户提款请求。", "sql": "-- 查询待处理提款申请 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.TodayOut AS WithdrawalAmount,\n c.BankAvailableBalance AS AvailableBalance,\n c.State AS RecordStatus\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.TodayOut > 0\nORDER BY c.TodayOut DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `TodayOut` 今日计划支出\n- 待处理提款申请应体现在此字段", "question_en": "Show all client withdrawals requested but not yet processed.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q17", "question_zh": "哪些客户已超过其信用额度?", "sql": "-- 查询超信用额度客户(使用 MarginLimit)\n-- 注意:MCAccount 无 CreditLimit 字段,应用 MarginLimit\nSELECT \n AccountID,\n Name AS AccountName,\n MarginLimit,\n MarketValue,\n MarginLimit - MarketValue AS AvailableCredit,\n CASE \n WHEN MarketValue > MarginLimit THEN '超额'\n WHEN MarketValue > MarginLimit * 0.8 THEN '接近限额'\n ELSE '正常'\n END AS Status\nFROM MCAccount\nWHERE MarginLimit > 0\n AND MarketValue > MarginLimit * 0.8\nORDER BY (MarketValue - MarginLimit) DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.MarginLimit` 保证金/信用限额(注意:无 `CreditLimit` 字段)\n- `MCAccount.MarketValue` 持仓市值\n- `MarginBLimit` 是单独借款限额,注意区分", "question_en": "Which clients have exceeded their credit limit?", "rating": 7, "execution_result": null, "result_note": "当前查询无超限客户", "tags": ["account", "limit", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q18", "question_zh": "今日收到的未清算支票总额是多少?", "sql": "-- 查询未清算支票 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.UnderdueCheque AS OverdueCheque,\n c.NextDayDueCheque AS PendingCheque,\n c.UnderdueCheque + c.NextDayDueCheque AS TotalUncleared\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE (c.UnderdueCheque > 0 OR c.NextDayDueCheque > 0) -- 注意:BCAccountCash 无这两个字段,需确认实际表\nORDER BY TotalUncleared DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash` 无 `UnderdueCheque` / `NextDayDueCheque` 字段,需业务确认支票数据存储位置", "question_en": "What is the total amount of uncleared cheques received today?", "rating": 4, "execution_result": null, "result_note": "当前查询无未清算支票", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q19", "question_zh": "列出今日起保证金比例发生变动的所有证券。", "sql": "-- 查询保证金比例变动的证券 (固定日期: 2026-04-02)\nSELECT \n i.InstrumentID,\n i.Name AS InstrumentName,\n i.MarginPercentage AS CurrentMarginRatio,\n i.MarginChangeDate\nFROM MCInstrument i\nWHERE i.MarginChangeDate = '2026-04-02'\nORDER BY i.MarginPercentage DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "i", "columns": []}}, "joins": []}, "explanation": "- `MCInstrument.MarginPercentage` 当前保证金比例\n- `MarginChangeDate` 变动日期", "question_en": "List all instruments with margin ratio changes effective today.", "rating": 7, "execution_result": null, "result_note": "当前查询无保证金比例变动记录", "tags": ["margin", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q20", "question_zh": "哪些公司行动的选择指令需在今日结束前提交?", "sql": "-- 查询今日截止的公司行动选择 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.ElectionPeriodTo AS Deadline,\n e.ElectionOptionFlag,\n e.Remark AS Description\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.ElectionPeriodTo = '2026-04-02'\n AND e.ElectionOptionFlag = 'Y'\n AND e.State = 'A';", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `ElectionPeriodTo` 选择截止日期\n- `ElectionOptionFlag = 'Y'` 需要选择", "question_en": "Which corporate action elections are due by end of day?", "rating": 8, "execution_result": null, "result_note": "当前查询无今日截止的选择", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q24", "question_zh": "有多少客户报表已生成成功但尚未发送?", "sql": "-- 查询已生成但未发送的报表\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n a.LastDailyStatementDate,\n a.LastMonthlyStatementDate,\n a.LastStatementGenerateTime,\n a.LastStatementSendTime,\n CASE \n WHEN a.LastStatementGenerateTime > a.LastStatementSendTime THEN '未发送'\n ELSE '已发送'\n END AS DeliveryStatus\nFROM MCAccount a\nWHERE a.LastStatementGenerateTime IS NOT NULL\n AND (a.LastStatementSendTime IS NULL \n OR a.LastStatementGenerateTime > a.LastStatementSendTime)\nORDER BY a.LastStatementGenerateTime DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `LastStatementGenerateTime` 报表生成时间\n- `LastStatementSendTime` 报表发送时间", "question_en": "How many client statements were successfully generated but not yet delivered?", "rating": 7, "execution_result": null, "result_note": "当前查询无未发送报表", "tags": ["ordering", "account", "filter", "statement"], "difficulty": "easy"}
{"qid": "Q25", "question_zh": "列出所有待批准的股票转移请求。", "sql": "-- 查询待批准的股票转移\nSELECT \n AccountID,\n InstrumentID,\n MovementType,\n MovementQuantity,\n FromAccountID,\n ToAccountID,\n RequestDate,\n ApprovalStatus,\n RequestedBy\nFROM BCAccountInstrumentMovement\nWHERE ApprovalStatus = 'P'\nORDER BY RequestDate DESC;", "schema_info": {"tables": {"BCAccountInstrumentMovement": {"alias": "BCAccountInstrumentMovement", "columns": []}}, "joins": []}, "explanation": "- 股票转移请求存储在专用表中\n- `ApprovalStatus = 'P'` 待批准状态", "question_en": "Show all pending stock movement requests that require approval.", "rating": 6, "execution_result": null, "result_note": "当前查询无待批准请求", "tags": ["filter", "ordering"], "difficulty": "easy"}
{"qid": "Q27", "question_zh": "列出所有超过3天的暂记账户分录。", "sql": "-- 查询超过3天的暂记账户分录 (2026-04-02)\n-- 说明:TCAccountCashMovement 是现金流水表\n-- NeedHoldFlag='Y' 表示暂记分录\n-- Amount - ReleasedAmount 表示未释放金额(暂记余额)\n-- 筛选未释放且超过3天的暂记分录\nSELECT \n cm.AccountID,\n cm.MovementID,\n cm.ValueDate,\n cm.CurrencyID,\n cm.Amount - ISNULL(cm.ReleasedAmount, 0) AS PendingBalance,\n cm.Remark,\n DATEDIFF(DAY, cm.ValueDate, '2026-04-02') AS DaysOutstanding\nFROM TCAccountCashMovement cm\nWHERE cm.NeedHoldFlag = 'Y'\n AND cm.Amount - ISNULL(cm.ReleasedAmount, 0) != 0\n AND DATEDIFF(DAY, cm.ValueDate, '2026-04-02') > 3\nORDER BY DaysOutstanding DESC, PendingBalance DESC;", "schema_info": {"tables": {"TCAccountCashMovement": {"alias": "cm", "columns": []}}, "joins": []}, "explanation": "- `TCAccountCashMovement` 存储现金流水记录\n- `NeedHoldFlag = 'Y'` 标识暂记(待确认)分录\n- `Amount - ReleasedAmount` 计算未释放的暂记余额\n- `DATEDIFF` 计算距今天数\n- `DATEDIFF > 3` 筛选超过3天的记录", "question_en": "List all suspense account entries older than 3 days.", "rating": 9, "execution_result": null, "result_note": "**查询结果:0条记录**\n\n当前没有超过3天未释放的暂记账户分录。所有暂记分录的 ReleasedAmount = Amount,已全部释放。", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q28", "question_zh": "哪些客户已请求更改结算货币?", "sql": "-- 查询请求更改结算货币的客户\n-- 说明:经查 MCAccountCurrency 表无 CurrencyChangeStatus/RequestedCurrencyID 等字段\n-- 数据库中没有专门的货币变更请求表\n-- 此查询基于账户货币历史时间表(HCAccountCurrencyTimetable)展示货币生效安排\nSELECT \n act.AccountID,\n mca.Name AS AccountName,\n act.CurrencyID AS Currency,\n act.EffectiveDateFrom,\n act.EffectiveDateTo,\n act.AccountTypeID\nFROM HCAccountCurrencyTimetable act\nINNER JOIN MCAccount mca ON act.AccountID = mca.AccountID\nWHERE act.EffectiveDateTo IS NULL\nORDER BY act.EffectiveDateFrom DESC;", "schema_info": {"tables": {"HCAccountCurrencyTimetable": {"alias": "act", "columns": []}, "MCAccount": {"alias": "mca", "columns": []}}, "joins": [{"type": "INNER", "on": "act.AccountID = mca.AccountID"}]}, "explanation": "- `HCAccountCurrencyTimetable` 记录账户货币生效时间表\n- `EffectiveDateTo IS NULL` 表示当前生效的货币配置\n- 如需货币变更请求功能,建议在系统中扩展相关表结构", "question_en": "Which clients have requested a change in settlement currency?", "rating": 4, "execution_result": null, "result_note": "**说明:** 数据库中没有专门的货币变更请求表。`MCAccountCurrency` 表仅记录账户当前货币配置,无变更请求字段。", "tags": ["join", "account", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q29", "question_zh": "列出后台系统中所有活跃用户账户及其最后登录日期。", "sql": "-- 查询活跃用户及其登录情况\nSELECT \n u.UserID,\n u.Name AS UserName,\n u.Status,\n u.LogonEnableFlag,\n u.LastLogonTime,\n u.BranchID,\n CASE u.CompanyAEFlag WHEN 'Y' THEN '公司经纪' ELSE '个人' END AS AEType,\n CASE \n WHEN u.LastLogonTime >= DATEADD(DAY, -7, GETDATE()) THEN '近7天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -30, GETDATE()) THEN '近30天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -90, GETDATE()) THEN '近90天活跃'\n ELSE '长期未登录'\n END AS ActivityStatus\nFROM MCUser u\nWHERE u.State = 'A'\n AND u.LogonEnableFlag = 'Y'\nORDER BY u.LastLogonTime DESC;", "schema_info": {"tables": {"MCUser": {"alias": "u", "columns": []}}, "joins": []}, "explanation": "- `MCUser` 存储用户信息\n- `LastLogonTime` 最后登录时间", "question_en": "List all active user accounts in the back office system with last login date.", "rating": 9, "execution_result": null, "result_note": "| UserID | UserName | Status | LogonEnableFlag | LastLogonTime | ActivityStatus |\n|--------|----------|--------|-----------------|---------------|----------------|\n| SUPPORT | SUPPORT | N | Y | 2026-04-08 | 近7天活跃 |\n| ROSANNA | ROSANNA | N | Y | 2025-10-21 | 长期未登录 |\n| SING | WONG LO SING | N | Y | 2025-10-21 | 长期未登录 |\n| LEONNG | LEON NG | N | Y | 2025-10-21 | 长期未登录 |", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q31", "question_zh": "指定日期或日期范围内收到的交易量(如成交金额)及相应佣金是多少?", "sql": "-- 交易量和佣金统计\nSELECT \n SUM(TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(TotalBoughtFee) AS TotalBuyCommission,\n SUM(TotalSoldConsideration) AS TotalSellConsideration,\n SUM(TotalSoldFee) AS TotalSellCommission,\n SUM(TotalBoughtConsideration) + SUM(TotalSoldConsideration) AS TotalConsideration,\n SUM(TotalBoughtFee) + SUM(TotalSoldFee) AS TotalCommission\nFROM BCAccountInstrument;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表记录了账户所有历史买卖交易\n- `TotalBoughtConsideration / TotalSoldConsideration`: 买卖成交金额", "question_en": "What is the trading volume (e.g., consideration) and corresponding commission amount received for a specific date or date range?", "rating": 9, "execution_result": null, "result_note": "| TotalBuyConsideration | TotalBuyCommission | TotalSellConsideration | TotalSellCommission | TotalConsideration | TotalCommission |\n|---------------------|-------------------|----------------------|--------------------|-------------------|-----------------|\n| 945,480,833.78 | 793,149.07 | 278,693,891.64 | 809,248.89 | 1,224,174,725.42 | 1,602,397.96 |", "tags": ["trade", "aggregation"], "difficulty": "easy"}
{"qid": "Q33", "question_zh": "今日是否有追缴保证金通知?", "sql": "-- 查询今日追缴保证金记录 (固定日期: 2026-04-02)\nSELECT \n m.AccountID,\n a.Name AS AccountName,\n m.CallForDeposit,\n m.CallForDepositDate,\n m.CallForDepositDays\nFROM HCAccountMarginCallForDeposit m\nINNER JOIN MCAccount a ON m.AccountID = a.AccountID\nWHERE m.CallForDepositDate = '2026-04-02';", "schema_info": {"tables": {"HCAccountMarginCallForDeposit": {"alias": "m", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "m.AccountID = a.AccountID"}]}, "explanation": "- `HCAccountMarginCallForDeposit` 记录追缴保证金信息\n- `CallForDeposit` 追缴金额", "question_en": "Have there been any margin calls today?", "rating": 9, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "margin", "filter"], "difficulty": "easy"}
{"qid": "Q37", "question_zh": "是否有正在进行的IPO事件,其认购状态如何?", "sql": "-- 查询进行中的IPO (2026年4月)\nSELECT \n i.InstrumentID,\n i.MarketID,\n i.Name AS InstrumentName,\n i.State AS InstrumentStatus,\n ip.Quantity AS SubscriptionLot,\n ip.SubscriptionAmount,\n ip.CreatedOn AS SubscriptionDate\nFROM MCInstrument i\nINNER JOIN MCInstrumentIPODetail ip ON i.InstrumentID = ip.InstrumentID\nWHERE YEAR(ip.CreatedOn) = 2026\n AND MONTH(ip.CreatedOn) = 4\nORDER BY ip.CreatedOn DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "i", "columns": []}, "MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": [{"type": "INNER", "on": "i.InstrumentID = ip.InstrumentID"}]}, "explanation": "- `MCInstrument` 表记录证券信息\n- `MCInstrumentIPODetail` 记录IPO认购详情", "question_en": "Are there any IPO events currently in progress, and what is their subscription status?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "filter", "ipo", "ordering"], "difficulty": "easy"}
{"qid": "Q38", "question_zh": "本月IPO事件的总佣金、手续费和保证金利息是多少?", "sql": "-- IPO相关费用汇总 (2026年4月)\nSELECT \n 'IPO Commission' AS FeeType,\n SUM(ip.SubscriptionAmount * 0.001) AS EstimatedFee\nFROM MCInstrumentIPODetail ip\nWHERE YEAR(ip.CreatedOn) = 2026\n AND MONTH(ip.CreatedOn) = 4;", "schema_info": {"tables": {"MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": []}, "explanation": "- IPO相关费用分散在多个表中\n- 需要关联 `BCAccountInstrument` 获取IPO交易费用", "question_en": "What are the total commission, handling fees, and margin interest for IPO events this month?", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["margin", "aggregation", "filter", "interest"], "difficulty": "easy"}
{"qid": "Q39", "question_zh": "列出今日需要执行的公司行动(如权益分派)。", "sql": "-- 查询今日生效的公司行动 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.MarketID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.BalanceDate,\n e.BalanceExDate,\n e.Remark,\n e.State\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.State = 'A'\n AND (\n e.BalanceDate = '2026-04-02'\n OR e.BalanceExDate = '2026-04-02'\n OR e.AutoHoldDate = '2026-04-02'\n OR e.AutoDeductDate = '2026-04-02'\n );", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录所有权益分派信息\n- `BalanceDate` 权益登记日期", "question_en": "List corporate actions (e.g., entitlements) that need to be performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q40", "question_zh": "列出今日执行的所有股票转移/移动。", "sql": "-- 今日股票转入/转出 (固定日期: 2026-04-02)\nSELECT \n AccountID,\n MarketID,\n InstrumentID,\n TodayIn AS QuantityIn,\n TodayOut AS QuantityOut,\n HoldForDeposit AS PendingDeposit,\n HoldForWithdrawal AS PendingWithdrawal\nFROM BCAccountInstrument\nWHERE TodayIn > 0 OR TodayOut > 0;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 记录股票持仓变动\n- `TodayIn` 今日转入数量", "question_en": "List all stock movements performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["filter"], "difficulty": "easy"}
{"qid": "Q41", "question_zh": "列出今日执行的所有现金划转。", "sql": "-- 今日现金变动汇总 (固定日期: 2026-04-02)\nSELECT \n b.AccountID,\n a.Name AS AccountName,\n b.TodayIn AS CashIn,\n b.TodayOut AS CashOut,\n b.BankAvailableBalance\nFROM BCAccountCash b\nINNER JOIN MCAccount a ON b.AccountID = a.AccountID\nWHERE b.TodayIn > 0 OR b.TodayOut > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "b", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "b.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash` 记录账户现金变动\n- `TodayIn` 今日现金流入", "question_en": "List all cash movements performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "filter", "cash"], "difficulty": "easy"}
{"qid": "Q42", "question_zh": "列出后台系统中的活跃用户。", "sql": "-- 查询后台系统活跃用户\nSELECT \n u.UserID,\n u.Name AS UserName,\n u.Status,\n u.LogonEnableFlag,\n u.LastLogonTime,\n u.BranchID,\n u.DepartmentID,\n CASE u.CompanyAEFlag WHEN 'Y' THEN '公司经纪' ELSE '个人' END AS AEType\nFROM MCUser u\nWHERE u.State = 'A'\n AND u.LogonEnableFlag = 'Y'\nORDER BY u.LastLogonTime DESC;", "schema_info": {"tables": {"MCUser": {"alias": "u", "columns": []}}, "joins": []}, "explanation": "- `MCUser` 存储系统用户信息\n- `State = 'A'` 用户状态正常", "question_en": "List active users in the back office.", "rating": 9, "execution_result": null, "result_note": "| UserID | UserName | Status | LogonEnableFlag | LastLogonTime | AEType |\n|--------|----------|--------|-----------------|---------------|--------|\n| SUPPORT | SUPPORT | N | Y | 2026-04-03 18:53:04 | 个人 |\n| ROSANNA | ROSANNA | N | Y | 2025-10-21 16:47:11 | 个人 |", "tags": ["filter", "ordering"], "difficulty": "easy"}
{"qid": "Q43", "question_zh": "列出持仓为负数(透支)的账户。", "sql": "-- 查询透支持仓账户\nSELECT \n AccountID,\n Name AS AccountName,\n MarketValue,\n AssetBalance,\n LiabilityBalance,\n MarginPosition,\n MarginFacilityFlag\nFROM MCAccount\nWHERE MarketValue < 0\n AND State = 'A'\nORDER BY MarketValue ASC;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MarketValue < 0` 筛选持仓为负的账户\n- 持仓为负通常表示账户存在透支或结算问题", "question_en": "List accounts with overdrawn positions.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginFacilityFlag |\n|-----------|-------------|-------------|-------------------|\n| P030012 | LAI YEE TAK HELEN | -112,196.60 | N |\n| P350022 | CHAN YAU KING*** | -92,950.00 | N |\n| P011212 | NG SIU PING | -12,352.00 | N |", "tags": ["account", "holding", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q44", "question_zh": "本月收到/支付的利息金额是多少(如客户借款利息和存款利息)?", "sql": "-- 本月利息收支汇总 (2026年4月)\nSELECT \n SUM(AccruedCreditInterest) AS CreditInterest,\n SUM(AccruedDebitInterest) AS DebitInterest,\n SUM(AccruedCreditInterest) - SUM(AccruedDebitInterest) AS NetInterest\nFROM BCAccountCash;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `BCAccountCash` 记录账户现金和利息信息\n- `AccruedCreditInterest` 应计存款利息", "question_en": "What is the interest amount received/paid this month (e.g., client debit interest and credit interest)?", "rating": 7, "execution_result": null, "result_note": "| CreditInterest | DebitInterest | NetInterest |\n|----------------|---------------|-------------|\n| 464.15 | 2,022.70 | -1,558.55 |", "tags": ["account", "aggregation", "interest"], "difficulty": "easy"}
{"qid": "Q48", "question_zh": "列出所有支持保证金的证券及其相应的保证金比例。", "sql": "-- 查询支持保证金的证券\nSELECT \n InstrumentID,\n Name AS InstrumentName,\n MarginPercentage AS MarginRatio,\n CASE \n WHEN MarginPercentage >= 0.7 THEN '高'\n WHEN MarginPercentage >= 0.5 THEN '中'\n WHEN MarginPercentage > 0 THEN '低'\n ELSE 'N/A'\n END AS RiskLevel,\n MarginLimitPerInstrument,\n CollateralRatio\nFROM MCInstrument\nWHERE MarginPercentage IS NOT NULL\n AND MarginPercentage > 0\n AND State = 'A'\nORDER BY MarginPercentage DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "MCInstrument", "columns": []}}, "joins": []}, "explanation": "- `MCInstrument` 存储证券信息\n- `MarginPercentage` 保证金比例", "question_en": "List all instruments that support margin and their corresponding margin ratios.", "rating": 9, "execution_result": null, "result_note": "| InstrumentID | InstrumentName | MarginRatio | RiskLevel |\n|-------------|----------------|-------------|-----------|\n| 00001 | CKH HOLDINGS(S) | 0.70 | 高 |\n| 00002 | CLP HOLDINGS(S) | 0.70 | 高 |\n| 00003 | HK & CHINA GAS(S) | 0.70 | 高 |\n\n(共767条记录)", "tags": ["margin", "limit", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q49", "question_zh": "本月、本季度和今年分别开了多少账户?", "sql": "-- 开户统计 (2026年4月)\nSELECT \n COUNT(CASE WHEN MONTH(OpenDate) = 4 AND YEAR(OpenDate) = 2026 THEN 1 END) AS April2026,\n COUNT(CASE WHEN DATEPART(QUARTER, OpenDate) = 2 AND YEAR(OpenDate) = 2026 THEN 1 END) AS Q2_2026,\n COUNT(CASE WHEN YEAR(OpenDate) = 2026 THEN 1 END) AS Year2026,\n COUNT(*) AS TotalAccounts,\n MIN(OpenDate) AS EarliestOpenDate,\n MAX(OpenDate) AS LatestOpenDate\nFROM MCAccount\nWHERE OpenDate IS NOT NULL;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.OpenDate` 账户开户日期\n- 按月、季度、年分别统计新开户数量", "question_en": "How many accounts were opened this month, this quarter, and this year?", "rating": 9, "execution_result": null, "result_note": "| April2026 | Q2_2026 | Year2026 | TotalAccounts | EarliestOpenDate | LatestOpenDate |\n|-----------|---------|----------|---------------|------------------|----------------|\n| 0 | 0 | 0 | 1,951 | 1993-03-05 | 2025-10-16 |", "tags": ["account", "limit", "filter", "aggregation"], "difficulty": "easy"}
{"qid": "Q50", "question_zh": "", "sql": "SELECT TOP\n\t15 c.ContractID,\n\tc.TradeDate,\n\tLTRIM( RTRIM( c.AccountID ) ) AS AccountID,\n\tLTRIM( RTRIM( c.MarketID ) ) AS MarketID,\n\tc.InstrumentID,\n\tc.BuySell,\n\tc.Quantity,\n\tc.Consideration,\n\tLTRIM( RTRIM( c.CurrencyID ) ) AS CurrencyID \nFROM\n\tdbo.TSBAccountContract c\n\tINNER JOIN dbo.MCAccount a ON c.AccountID = a.AccountID \nWHERE\n\tCAST ( c.TradeDate AS DATE ) = '2026-04-02' \n\tAND LTRIM( RTRIM( a.HouseAccountFlag ) ) = 'N' \nORDER BY\n\tc.ContractID;", "schema_info": {"tables": {"TSBAccountContract": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "", "question_en": "列出今天所有客戶的交易記錄", "rating": null, "execution_result": null, "result_note": "| ContractID | TradeDate | AccountID | MarketID | InstrumentID | BuySell | Quantity | Consideration | CurrencyID |\n| :--------- | :--------- | :-------- | :------- | :----------- | :------ | :------- | :------------ | :--------- |\n| B02403846 | 2026-04-02 | P011206 | HKEX | 01810 | B | 600 | 18360 | HKD |\n| B02403847 | 2026-04-02 | P011202 | HKEX | 01810 | B | 200 | 6120 | HKD |\n\n\n\n\n\n---\n\n## 附录:关键表说明\n\n| 表名 | 说明 | 关键字段 |\n|------|------|---------|\n| MCAccount | 账户主表 | AccountID, Name, MarketValue, MarginFacilityFlag |\n| MCUser | 用户表 | UserID, Name, Status, LogonEnableFlag |\n| BCAccountInstrument | 账户持仓 | AccountID, MarketID, Settled, DueBuy, DueSell |\n| BCAccountCash | 账户现金 | AccountID, TodayIn, TodayOut, AccruedInterest |\n| HCAccountMarginCallForDeposit | 追缴保证金 | AccountID, CallForDeposit, CallForDepositDate |\n| MCInstrument | 证券表 | InstrumentID, Name, MarginPercentage |\n| MCInstrumentIPODetail | IPO详情 | InstrumentID, Quantity, SubscriptionAmount |\n| MSBEntitlement | 权益分派 | EntitlementID, BalanceDate, BalanceExDate |\n| MCBroker | 经纪商 | BrokerID, Name |\n| MCLocation | 托管位置 | LocationID, Name, CCASSFlag |\n| HCExchangeRate | 汇率 | ExchangeRateID, ValueDate |\n| HCAccountCashRecord | 现金记录 | AccountID, ValueDate, LedgerBalance |\n\n---\n\n**文档结束**", "tags": ["join", "limit", "filter", "ordering"], "difficulty": "easy"}
+15
View File
@@ -0,0 +1,15 @@
{"qid": "Q1", "question_zh": "按对手方列出截至[日期]的所有未结算交易。", "sql": "-- 按对手方统计截至 2026-04-02 的未结算交易\n-- 使用 TSBBrokerContract(经纪商合约表),按 BrokerID(对手方经纪商)分组\n-- SettleStatus='U' 表示未结算;CashSettleDate <= '2026-04-02' 筛选截至日\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n COUNT(*) AS UnsettledTradeCount,\n SUM(b.SettleQuantity) AS TotalUnsettledQty,\n SUM(b.SettleAmount) AS TotalUnsettledAmount,\n MIN(b.BuySell) + '~' + MAX(b.BuySell) AS BuySellRange,\n MIN(b.CashSettleDate) AS EarliestSettleDate,\n MAX(b.CashSettleDate) AS LatestSettleDate\nFROM TSBBrokerContract b\nLEFT JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.SettleStatus = 'U'\n AND b.CashSettleDate <= '2026-04-02'\nGROUP BY b.BrokerID, m.Name\nORDER BY TotalUnsettledAmount DESC;", "schema_info": {"tables": {"TSBBrokerContract": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "LEFT", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `TSBBrokerContract` 是经纪商/对手方合约表,记录与外部对手方的交易合约,`BrokerID` 即对手方标识\n- `SettleStatus = 'U'` 表示未结算;`CashSettleDate <= '2026-04-02'` 筛选截至日未结清的合约\n- 关联 `MCBroker` 获取对手方经纪商名称\n- 按 `BrokerID` 分组汇总未结算数量和金额", "question_en": "Show all unsettled trades as of [date] grouped by counterparty.", "rating": 9, "execution_result": null, "result_note": "| BrokerID | BrokerName | UnsettledTradeCount | TotalUnsettledQty | TotalUnsettledAmount | BuySellRange | EarliestSettleDate | LatestSettleDate |\n|----------|-----------|---------------------|-------------------|---------------------|--------------|---------------------|-------------------|\n| CCASS | CCASS | 622 | 40,459,253 | 44,173,571.06 | B~S | 2025-07-30 | 2026-04-02 |\n\n> **注**:CCASS(Hong Kong Securities Clearing Company Limited)是香港交易所的中央结算机构,作为交易所交易的核心对手方。622笔未结算合约均为 HKEX 市场。", "tags": ["join", "ordering", "broker", "filter", "trade", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q2", "question_zh": "列出今日所有客户账户之间的股票转移记录。", "sql": "-- 查询今日客户账户间股票转移(参考日期:2026-04-02)\n-- 使用 TSBAccountInstrumentMovement,MovementType='T' 表示账户间转移\n-- ValueDate 为转移生效日期,关联 MCInstrument 获取证券名称\nSELECT \n m.MovementID,\n m.AccountID AS FromAccountID,\n m.TransferToAccountID,\n m.InstrumentID,\n i.Name AS InstrumentSymbol,\n m.MovementType,\n m.Quantity AS TransferQuantity,\n m.ValueDate AS TransferDate\nFROM TSBAccountInstrumentMovement m\nLEFT JOIN MCInstrument i ON m.InstrumentID = i.InstrumentID\nWHERE m.MovementType = 'T'\n AND m.ValueDate = '2026-04-02'\nORDER BY m.ValueDate;", "schema_info": {"tables": {"TSBAccountInstrumentMovement": {"alias": "m", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "LEFT", "on": "m.InstrumentID = i.InstrumentID"}]}, "explanation": "- `TSBAccountInstrumentMovement` 是持仓变动流水表,记录所有证券变动事件\n- `MovementType = 'T'`(Transfer)特指**账户间股票转移**,对应 `TransferToAccountID` 记录目标账户\n- `ValueDate` 是转移生效日期,可按日期过滤\n- 关联 `MCInstrument` 获取证券代码/名称\n- 注意:`BCAccountInstrument` 的 `TodayIn/TodayOut` 是**实时快照**,不带历史日期维度,不能用于查历史转移", "question_en": "List all stock transfers between client accounts performed today.", "rating": 9, "execution_result": null, "result_note": "当前查询无结果(测试环境中 `TSBAccountInstrumentMovement` 的 `MovementType='T'` 最新记录为 2025-10-21,无 2026-04-02 的账户间转移数据)", "tags": ["join", "ordering", "filter", "account", "left_join"], "difficulty": "hard"}
{"qid": "Q7", "question_zh": "今日结算后现金余额为负的账户列表。", "sql": "-- 查询现金余额为负的账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.Settled AS CashBalance,\n c.UnderdueCheque,\n c.BankAvailableBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.Settled < 0\nORDER BY c.Settled ASC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash.Settled` 表示已结算现金余额\n- 负数表示账户透支\n- 关联 `MCAccount` 获取账户名称", "question_en": "List accounts with negative cash balance after today's settlement.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | CurrencyID | CashBalance |\n|-----------|------------|------------|-------------|\n| M050009 | NG SUN SHU*** | HKD | -4,678,978.42 |\n| P050667 | WONG YIM HUNG | HKD | -780,196.94 |\n| M050521 | LO CHUN YIP | HKD | -290,487.54 |\n\n(共55个账户现金余额为负)", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q11", "question_zh": "哪些客户尚未缴纳IPO申购款?", "sql": "-- 查询未缴纳IPO申购款的账户\nSELECT \n a.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.TotalBoughtQuantity AS SubscriptionLot,\n bi.TotalBoughtConsideration AS SubscriptionAmount\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nINNER JOIN MCInstrumentIPODetail ip ON bi.InstrumentID = ip.InstrumentID\nWHERE ip.State = 'A'\n AND bi.TotalBoughtConsideration > 0\n AND bi.TotalBoughtFee = 0\nORDER BY bi.TotalBoughtConsideration DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}, "MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}, {"type": "INNER", "on": "bi.InstrumentID = ip.InstrumentID"}]}, "explanation": "- 通过比对买卖数量和手续费判断是否缴款\n- `TotalBoughtConsideration > 0` 有认购\n- `TotalBoughtFee = 0` 未支付手续费", "question_en": "Which clients have not yet paid their IPO subscription money?", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "ordering"], "difficulty": "hard"}
{"qid": "Q15", "question_zh": "本月应付给介绍经纪人的佣金返佣总额是多少?", "sql": "-- 查询本月应付返佣 (2026年4月)\n-- 注意:BCAccountInstrument 无 UpdatedAt 字段,用 LastTransactionDate 过滤本月有交易的账户\n-- 说明:TotalBoughtFee/TotalSoldFee 为历史累计字段,此处统计近期活跃账户的累计佣金供参考\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE YEAR(bi.LastTransactionDate) = 2026\n AND MONTH(bi.LastTransactionDate) = 4\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee + bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCRebateScheme` 可能存储返佣规则\n- 按AE汇总佣金", "question_en": "What is the total commission rebate payable to introducing brokers this month?", "rating": 6, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q21", "question_zh": "截至昨日的客户借方余额应计利息是多少?", "sql": "-- 查询客户借方余额应计利息 (截至2026-04-01)\nSELECT \n SUM(AccruedDebitInterest) AS TotalDebitInterestAccrued,\n SUM(AccruedCreditInterest) AS TotalCreditInterestAccrued,\n SUM(AccruedDebitInterest) - SUM(AccruedCreditInterest) AS NetDebitInterest,\n COUNT(DISTINCT AccountID) AS AccountCount\nFROM BCAccountCash\nWHERE AccruedDebitInterest > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `AccruedDebitInterest` 借款应计利息\n- `AccruedCreditInterest` 存款应计利息", "question_en": "What is the interest accrued on client debit balances as of yesterday?", "rating": 8, "execution_result": null, "result_note": "| TotalDebitInterestAccrued | TotalCreditInterestAccrued | NetDebitInterest | AccountCount |\n|---------------------------|---------------------------|-----------------|-------------|\n| 2,022.70 | 464.15 | 1,558.55 | 55 |", "tags": ["filter", "account", "interest", "cash", "aggregation"], "difficulty": "hard"}
{"qid": "Q22", "question_zh": "列出今日所有公司账户与客户账户之间的现金划转。", "sql": "-- 查询公司账户与客户账户现金划转 (固定日期: 2026-04-02)\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n a.AccountType,\n c.CurrencyID,\n c.TodayIn AS CashInflow,\n c.TodayOut AS CashOutflow,\n c.Settled AS CurrentBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE (c.TodayIn > 0 OR c.TodayOut > 0)\nORDER BY c.TodayIn + c.TodayOut DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- 公司账户与客户账户通过 `AccountType` 区分\n- `TodayIn/TodayOut` 记录现金流动", "question_en": "List all cash movements between house and client accounts today.", "rating": 7, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q23", "question_zh": "列出所有逾期未付保证金利息的账户。", "sql": "-- 查询逾期保证金利息账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.LoanInterestMarginOverdue AS MarginOverdueInterest,\n c.LoanInterestMarginBOverdue AS MarginBOverdueInterest,\n c.LoanInterestOverdue AS GeneralOverdueInterest\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.LoanInterestMarginOverdue > 0 \n OR c.LoanInterestMarginBOverdue > 0\n OR c.LoanInterestOverdue > 0\nORDER BY (c.LoanInterestMarginOverdue + c.LoanInterestMarginBOverdue + c.LoanInterestOverdue) DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `LoanInterestMarginOverdue` 保证金账户逾期利息\n- `LoanInterestMarginBOverdue` B类保证金逾期利息", "question_en": "Show all accounts with overdue margin interest payments.", "rating": 8, "execution_result": null, "result_note": "当前查询无逾期利息记录", "tags": ["join", "ordering", "margin", "filter", "account", "interest"], "difficulty": "hard"}
{"qid": "Q26", "question_zh": "本月各交易所的结算费用明细如何?", "sql": "-- 按交易所统计结算费用 (2026年4月)\n-- 说明:BCAccountInstrument 表中 TotalBoughtFee/TotalSoldFee 是持仓级别的交易费用字段\n-- LastTransactionDate 表示该持仓最后交易日期\n-- 查询逻辑:筛选最后交易日期在本月内的持仓记录,按交易所汇总交易费用\nSELECT \n bi.MarketID,\n m.MarketName,\n SUM(bi.TotalBoughtFee) AS TotalBuyFee,\n SUM(bi.TotalSoldFee) AS TotalSellFee,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalSettlementFee,\n COUNT(DISTINCT bi.AccountID) AS TradingAccountCount\nFROM BCAccountInstrument bi\nINNER JOIN MCMarket m ON bi.MarketID = m.MarketID\nWHERE bi.LastTransactionDate >= '2026-04-01' AND bi.LastTransactionDate < '2026-05-01'\nGROUP BY bi.MarketID, m.MarketName\nORDER BY TotalSettlementFee DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCMarket": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.MarketID = m.MarketID"}]}, "explanation": "- `BCAccountInstrument` 存储持仓级别信息,包含各持仓的交易费用累计\n- `MCMarket` 存储市场信息,提供市场名称\n- `LastTransactionDate` 用于过滤本月有交易的持仓记录\n- 按市场分组汇总结算费用", "question_en": "What is the breakdown of settlement fees by exchange for this month?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "trade", "aggregation", "date_range"], "difficulty": "hard"}
{"qid": "Q30", "question_zh": "按结算日期划分的未结算交易总风险敞口是多少?", "sql": "-- 按结算日期分组的未结算交易敞口\nSELECT \n SettlementType,\n SUM(Amount) AS TotalExposure\nFROM (\n SELECT 'DueBuy_T1' AS SettlementType, SUM(DueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'DueSell_T1' AS SettlementType, SUM(DueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueBuy' AS SettlementType, SUM(NextDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueSell' AS SettlementType, SUM(NextDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueBuy' AS SettlementType, SUM(NextTwoDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueSell' AS SettlementType, SUM(NextTwoDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueBuy' AS SettlementType, SUM(TodayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueSell' AS SettlementType, SUM(TodayDueSell) AS Amount FROM BCAccountInstrument\n) t\nGROUP BY SettlementType\nORDER BY SettlementType;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表包含所有账户的证券持仓和交收信息\n- `DueBuy/DueSell` 表示T+1到期的买卖数量", "question_en": "What is the total exposure from unsettled trades by settlement date?", "rating": 8, "execution_result": null, "result_note": "| SettlementType | TotalExposure |\n|----------------|---------------|\n| DueBuy_T1 | 0 |\n| DueSell_T1 | 0 |\n| NextDayDueBuy | 0 |\n| NextDayDueSell | 0 |\n| NextTwoDayDueBuy | 0 |\n| NextTwoDayDueSell | 0 |\n| TodayDueBuy | 1,800 |\n| TodayDueSell | 1,000 |\n\n**注:** `DueBuy/DueSell` 等字段表示应交收数量(T+1/T+2/今日),非金额敞口。如需金额敞口,需乘以价格。", "tags": ["union", "trade", "ordering", "aggregation"], "difficulty": "hard"}
{"qid": "Q34", "question_zh": "保证金账户前20大持仓(按市值)是多少?", "sql": "-- 保证金账户按市值排序的前20持仓\nSELECT TOP 20\n a.AccountID,\n a.Name AS AccountName,\n a.MarketValue,\n a.MarginDebitRatio AS MarginDebitBalanceRatio,\n a.MarginPosition,\n a.CallForDeposit,\n a.MarginFacilityFlag\nFROM MCAccount a\nWHERE a.MarginFacilityFlag = 'Y'\n AND a.State = 'A'\n AND a.MarketValue > 0\nORDER BY a.MarketValue DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 表包含所有账户信息\n- `MarginFacilityFlag = 'Y'` 筛选保证金账户", "question_en": "What are the top 20 holdings (based on market value) for margin accounts?", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginPosition |\n|-----------|-------------|------------|----------------|\n| M050009 | NG SUN SHU*** | 57,420,000 | 35,515,021.58 |\n| M050013 | NG CHUNG WAI*** | 19,504,520 | 10,918,958.78 |\n| M050193 | WONG KING YIU*** ^ | 11,682,920 | 3,340,099.05 |\n| P020160 | LAW SHIU MING DENNIS | 7,520,370 | 0 |\n| P030078 | MAK SUI BING | 7,120,309.94 | 0 |\n| P051101 | CHUNG CHUNG YEE | 7,117,808.04 | 0 |\n| M050170 | FUNG LAI FONG ANNA | 7,009,227.25 | 4,136,857 |\n| P220005 | LAI KAM SUI # | 5,837,102.10 | 97.97 |\n| P280628 | CHAN KWOK MO # | 5,761,997.48 | 62,508.23 |\n| P280455 | LEUNG KA CHI # | 5,487,971.20 | -64,981.22 |\n\n(共20条记录,以上展示前10条)", "tags": ["ordering", "holding", "margin", "filter", "limit", "account"], "difficulty": "hard"}
{"qid": "Q35", "question_zh": "列出本月按客户主任分组的佣金总额,以及相应的成交金额和返佣金额。", "sql": "-- 按经纪商/客户主任分组的佣金统计\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee) AS TotalBuyCommission,\n SUM(bi.TotalSoldFee) AS TotalSellCommission,\n SUM(bi.TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(bi.TotalSoldConsideration) AS TotalSellConsideration,\n SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE a.State = 'A'\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCAccount.AEID` 关联经纪商/客户主任\n- `BCAccountInstrument` 包含交易费用数据", "question_en": "List the total commission received this month by AE, along with corresponding consideration and rebate amounts.", "rating": 8, "execution_result": null, "result_note": "| AEID | AEName | AccountCount | TotalBuyCommission | TotalSellCommission | TotalCommission |\n|------|--------|-------------|-------------------|--------------------|----------------|\n| C01 | CHAN YUET HUNG | 628 | 183,244.64 | 187,220.59 | 370,465.23 |\n| C28 | CHAN SHU SHAN | 405 | 179,275.89 | 176,760.39 | 356,036.28 |\n| C05 | CENTRAL | 517 | 97,368.51 | 102,819.88 | 200,188.39 |\n| C33 | LEON NG | 13 | 71,541.06 | 72,620.60 | 144,161.66 |\n| C07 | CHAN WING PAI | 75 | 73,255.68 | 69,115.58 | 142,371.26 |\n| C10 | TOKWAWAN / KOWLOON CITY | 369 | 51,059.78 | 57,288.86 | 108,348.64 |\n| C08 | WONG HON KONG | 380 | 47,505.15 | 46,300.39 | 93,805.54 |\n| C36 | Name Of C36 | 146 | 40,945.66 | 35,682.86 | 76,628.52 |\n| C66 | CHEUNG YUK LING IVA | 17 | 24,458.82 | 22,723.18 | 47,182.00 |\n| C19 | WONG LO SING | 60 | 13,337.69 | 13,912.30 | 27,249.99 |\n\n(共15个AE有佣金记录,以上展示前10条)\n\n**注:** 当前SQL无日期条件,统计所有历史累计佣金。如需\"本月\"佣金,需添加 `LastTransactionDate >= '2026-04-01'` 条件。", "tags": ["join", "ordering", "filter", "account", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q45", "question_zh": "不同经纪商(如非中央结算系统持仓)的客户总持仓是多少?", "sql": "-- 按托管位置统计持仓(非CCASS)\nSELECT \n loc.LocationID,\n loc.Name AS LocationName,\n COUNT(DISTINCT bi.AccountID) AS AccountCount,\n SUM(bi.Settled) AS TotalQuantity,\n SUM(bi.CostAmount) AS TotalCostAmount\nFROM BCAccountLocationInstrument bi\nINNER JOIN MCLocation loc ON bi.LocationID = loc.LocationID\nWHERE loc.CCASSFlag = 'N'\nGROUP BY loc.LocationID, loc.Name\nORDER BY TotalQuantity DESC;", "schema_info": {"tables": {"BCAccountLocationInstrument": {"alias": "bi", "columns": []}, "MCLocation": {"alias": "loc", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.LocationID = loc.LocationID"}]}, "explanation": "- `BCAccountLocationInstrument` 记录按托管位置分类的持仓\n- `MCLocation` 存储托管位置信息", "question_en": "What is the total client holding at different broker firms (e.g., non-CCASS locations)?", "rating": 7, "execution_result": null, "result_note": "当前查询需要验证 Location 表关联", "tags": ["join", "ordering", "holding", "broker", "filter", "account", "aggregation"], "difficulty": "hard"}
{"qid": "Q46", "question_zh": "支付给其他经纪商的佣金是多少?", "sql": "-- 查询支付给其他经纪商的佣金\nSELECT \n b.BrokerID,\n b.Name AS BrokerName,\n SUM(bc.Commission) AS TotalCommission,\n SUM(bc.Consideration) AS TotalConsideration\nFROM MCBroker b\nINNER JOIN BCBrokerCash bc ON b.BrokerID = bc.BrokerID\nWHERE bc.Commission > 0\nGROUP BY b.BrokerID, b.Name\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCBroker": {"alias": "b", "columns": []}, "BCBrokerCash": {"alias": "bc", "columns": []}}, "joins": [{"type": "INNER", "on": "b.BrokerID = bc.BrokerID"}]}, "explanation": "- `MCBroker` 存储经纪商信息\n- `BCBrokerCash` 可能包含经纪商现金和佣金数据", "question_en": "How much commission has been paid to other brokers?", "rating": 6, "execution_result": null, "result_note": "当前查询需要验证经纪商佣金表关联", "tags": ["join", "ordering", "broker", "filter", "aggregation"], "difficulty": "hard"}
{"qid": "Q47", "question_zh": "今日/指定日期发放了多少份日结单或月结单?", "sql": "-- 查询报表发放统计 (2026-04-02)\nSELECT \n 'Daily Statement' AS StatementType,\n COUNT(*) AS StatementCount\nFROM MCAccount\nWHERE LastDailyStatementDate = '2026-04-02'\nUNION ALL\nSELECT \n 'Monthly Statement' AS StatementType,\n COUNT(*) AS StatementCount\nFROM MCAccount\nWHERE LastMonthlyStatementDate = '2026-04-02';", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 记录账户报表发送日期\n- `LastDailyStatementDate` 最近日结单发送日期", "question_en": "How many daily or monthly statements were issued today / on a specific date?", "rating": 9, "execution_result": null, "result_note": "", "tags": ["union", "filter", "aggregation"], "difficulty": "hard"}
+6
View File
@@ -0,0 +1,6 @@
{"qid": "Q6", "question_zh": "所有货币的客户现金总余额是多少?", "sql": "-- 按货币统计客户现金余额\nSELECT \n CurrencyID,\n COUNT(DISTINCT AccountID) AS AccountCount,\n SUM(Settled) AS TotalSettledBalance,\n SUM(AccruedCreditInterest) AS TotalCreditInterest,\n SUM(AccruedDebitInterest) AS TotalDebitInterest,\n SUM(Settled) + SUM(AccruedCreditInterest) - SUM(AccruedDebitInterest) AS NetBalance\nFROM BCAccountCash\nGROUP BY CurrencyID\nORDER BY NetBalance DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `BCAccountCash` 记录账户现金余额\n- `Settled` 已结算余额\n- `AccruedCreditInterest` 应计存款利息\n- `AccruedDebitInterest` 应计借款利息", "question_en": "What is the total client cash balance across all currencies?", "rating": 9, "execution_result": null, "result_note": "| CurrencyID | AccountCount | TotalSettledBalance | NetBalance |\n|------------|-------------|--------------------|------------|\n| HKD | 2,906 | 52,195,305.77 | 52,195,305.77 |\n| TWD | 2 | -27,676.60 | -27,676.60 |\n| USD | 175 | 0 | 0 |\n| CNY | 95 | 0 | 0 |\n| GBP | 1 | 0 | 0 |", "tags": ["ordering", "account", "cash", "aggregation"], "difficulty": "medium"}
{"qid": "Q12", "question_zh": "本月累计的结算失败罚金是多少?", "sql": "-- 查询本月结算失败罚金 (2026年4月)\n-- 注意:BCAccountInstrument 无 FailedTradePenalty 字段,需另找结算罚金存储位置\n-- 目前未找到结算失败罚金字段,建议通过 TSBBrokerContract 或 BCBrokerCash 进一步排查\nSELECT \n COUNT(*) AS FailedTradeCount,\n MarketID\nFROM BCAccountInstrument\nWHERE YEAR(LastTransactionDate) = 2026\n AND MONTH(LastTransactionDate) = 4\nGROUP BY MarketID;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 无 `FailedTradePenalty` 字段,原始 SQL 会报错\n- `TSBBrokerContract` 或 `BCBrokerCash` 中可能存储结算相关费用,需进一步确认", "question_en": "What is the total failed trade penalty incurred this month?", "rating": 3, "execution_result": null, "result_note": "当前查询无结果(BCAccountInstrument 表无 FailedTradePenalty 字段,无法统计结算罚金)", "tags": ["filter", "aggregation"], "difficulty": "medium"}
{"qid": "Q13", "question_zh": "列出今日到期的所有股票借贷交易。", "sql": "-- 查询今日到期的股票借贷 (参考日期: 2026-04-02)\n-- MCMarket 表仅包含 HKEX/OSL/SETW,无独立借贷市场标识\n-- 股票借贷可能在持仓变动类型 HoldType 中标识,或在专门的 StockBorrowing 表中\n-- 此 SQL 按 DueBuy/DueSell 显示当前待交收证券,作为借贷合约的近似替代\nSELECT \n bi.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.DueBuy AS BorrowQuantity,\n bi.DueSell AS LoanQuantity,\n bi.DueBuy - bi.DueSell AS NetBorrow\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nWHERE bi.DueBuy > 0 OR bi.DueSell > 0;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}]}, "explanation": "- `DueBuy/DueSell` 表示待交收数量(借款买入/借出卖出),反映股票借贷待到期情况\n- `MCMarket` 表无 `MarketType='BORROW'` 标识,现有市场仅为 HKEX/OSL/SETW\n- 股票借贷详情可能存储在 `TSBAccountLoanContract` 或其他借贷专用表中,需业务确认", "question_en": "List all stock borrow/loan transactions due to settle today.", "rating": 5, "execution_result": null, "result_note": "当前查询无结果(BCAccountInstrument 中 DueBuy/DueSell 均为 0,无待交收证券)", "tags": ["join", "trade", "filter"], "difficulty": "medium"}
{"qid": "Q16", "question_zh": "列出T+2交易缺少结算指令的账户。", "sql": "-- 查询T+2待交收但缺少指令的账户\n-- 注意:BCAccountInstrumentInstruction 表不存在,需改用 TSBSettlementInstruction\nSELECT \n bi.AccountID,\n a.Name AS AccountName,\n bi.InstrumentID,\n i.Name AS InstrumentName,\n bi.NextDayDueBuy AS T2DueBuy,\n bi.NextDayDueSell AS T2DueSell\nFROM BCAccountInstrument bi\nINNER JOIN MCAccount a ON bi.AccountID = a.AccountID\nINNER JOIN MCInstrument i ON bi.InstrumentID = i.InstrumentID\nWHERE (bi.NextDayDueBuy > 0 OR bi.NextDayDueSell > 0)\n AND NOT EXISTS (\n SELECT 1 FROM TSBSettlementInstruction si\n WHERE si.AccountOrBrokerID = bi.AccountID\n AND si.InstrumentID = bi.InstrumentID\n AND si.State IN ('P','A')\n );", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCAccount": {"alias": "a", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}, "TSBSettlementInstruction": {"alias": "si", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.AccountID = a.AccountID"}, {"type": "INNER", "on": "bi.InstrumentID = i.InstrumentID"}]}, "explanation": "- `NextDayDueBuy/NextDayDueSell` T+2交收数量(次日到期)\n- `TSBSettlementInstruction` 是结算指令表,通过 `NOT EXISTS` 排除已有指令的记录\n- `BCAccountInstrumentInstruction` 表不存在,不能使用", "question_en": "Show accounts where settlement instruction is missing for T+2 trades.", "rating": 6, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "account", "filter", "trade"], "difficulty": "medium"}
{"qid": "Q32", "question_zh": "各市场客户不同资产(如股票、债券、基金、虚拟资产)的总持仓是多少?", "sql": "-- 按市场统计客户持仓\nSELECT \n b.MarketID,\n COUNT(DISTINCT b.AccountID) AS AccountCount,\n SUM(b.Settled) AS TotalQuantity,\n SUM(b.CostAmount) AS TotalCostAmount,\n SUM(b.TotalBoughtQuantity) AS TotalBoughtQty,\n SUM(b.TotalSoldQuantity) AS TotalSoldQty\nFROM BCAccountInstrument b\nGROUP BY b.MarketID\nORDER BY TotalCostAmount DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "b", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表记录账户在各市场的持仓\n- `MarketID` 区分不同市场", "question_en": "What is the total client holding of different assets (e.g., stocks, bonds, funds, virtual assets) by each market?", "rating": 8, "execution_result": null, "result_note": "| MarketID | AccountCount | TotalQuantity | TotalCostAmount | TotalBoughtQty | TotalSoldQty |\n|----------|-------------|---------------|-----------------|---------------|-------------|\n| HKEX | 2,102 | 717,471,548 | 87,813,213.45 | 1,015,923,906 | 298,452,798 |\n| SETW | 2 | 3,100 | 32,298.50 | 4,100 | 1,000 |", "tags": ["account", "holding", "ordering", "aggregation"], "difficulty": "medium"}
{"qid": "Q36", "question_zh": "各市场(如港股T+1和T+2、美股T+1)的待结算金额是多少?", "sql": "-- 按市场统计待结算金额\nSELECT \n MarketID,\n SUM(DueBuy + DueSell) AS TotalPendingQty,\n SUM(NextDayDueBuy + NextDayDueSell) AS T2TotalPendingQty\nFROM BCAccountInstrument\nWHERE DueBuy > 0 OR DueSell > 0 OR NextDayDueBuy > 0 OR NextDayDueSell > 0\nGROUP BY MarketID;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 记录各市场的待交收数量\n- `DueBuy/DueSell` 对应T+1交收", "question_en": "What is the pending settlement amount for each market (e.g., HK T+1 & T+2, US T+1)?", "rating": 7, "execution_result": null, "result_note": "| MarketID | TotalPendingQty | T2TotalPendingQty |\n|----------|----------------|------------------|\n| HKEX | 0 | 0 |\n| SETW | 0 | 0 |", "tags": ["filter", "aggregation"], "difficulty": "medium"}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,30 @@
{"qid": "Q1", "question_zh": "按对手方列出截至[日期]的所有未结算交易。", "sql": "-- 按对手方统计截至 2026-04-02 的未结算交易\n-- 使用 TSBBrokerContract(经纪商合约表),按 BrokerID(对手方经纪商)分组\n-- SettleStatus='U' 表示未结算;CashSettleDate <= '2026-04-02' 筛选截至日\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n COUNT(*) AS UnsettledTradeCount,\n SUM(b.SettleQuantity) AS TotalUnsettledQty,\n SUM(b.SettleAmount) AS TotalUnsettledAmount,\n MIN(b.BuySell) + '~' + MAX(b.BuySell) AS BuySellRange,\n MIN(b.CashSettleDate) AS EarliestSettleDate,\n MAX(b.CashSettleDate) AS LatestSettleDate\nFROM TSBBrokerContract b\nLEFT JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.SettleStatus = 'U'\n AND b.CashSettleDate <= '2026-04-02'\nGROUP BY b.BrokerID, m.Name\nORDER BY TotalUnsettledAmount DESC;", "schema_info": {"tables": {"TSBBrokerContract": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "LEFT", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `TSBBrokerContract` 是经纪商/对手方合约表,记录与外部对手方的交易合约,`BrokerID` 即对手方标识\n- `SettleStatus = 'U'` 表示未结算;`CashSettleDate <= '2026-04-02'` 筛选截至日未结清的合约\n- 关联 `MCBroker` 获取对手方经纪商名称\n- 按 `BrokerID` 分组汇总未结算数量和金额", "question_en": "Show all unsettled trades as of [date] grouped by counterparty.", "rating": 9, "execution_result": null, "result_note": "| BrokerID | BrokerName | UnsettledTradeCount | TotalUnsettledQty | TotalUnsettledAmount | BuySellRange | EarliestSettleDate | LatestSettleDate |\n|----------|-----------|---------------------|-------------------|---------------------|--------------|---------------------|-------------------|\n| CCASS | CCASS | 622 | 40,459,253 | 44,173,571.06 | B~S | 2025-07-30 | 2026-04-02 |\n\n> **注**:CCASS(Hong Kong Securities Clearing Company Limited)是香港交易所的中央结算机构,作为交易所交易的核心对手方。622笔未结算合约均为 HKEX 市场。", "tags": ["join", "ordering", "broker", "filter", "trade", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q2", "question_zh": "列出今日所有客户账户之间的股票转移记录。", "sql": "-- 查询今日客户账户间股票转移(参考日期:2026-04-02)\n-- 使用 TSBAccountInstrumentMovement,MovementType='T' 表示账户间转移\n-- ValueDate 为转移生效日期,关联 MCInstrument 获取证券名称\nSELECT \n m.MovementID,\n m.AccountID AS FromAccountID,\n m.TransferToAccountID,\n m.InstrumentID,\n i.Name AS InstrumentSymbol,\n m.MovementType,\n m.Quantity AS TransferQuantity,\n m.ValueDate AS TransferDate\nFROM TSBAccountInstrumentMovement m\nLEFT JOIN MCInstrument i ON m.InstrumentID = i.InstrumentID\nWHERE m.MovementType = 'T'\n AND m.ValueDate = '2026-04-02'\nORDER BY m.ValueDate;", "schema_info": {"tables": {"TSBAccountInstrumentMovement": {"alias": "m", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "LEFT", "on": "m.InstrumentID = i.InstrumentID"}]}, "explanation": "- `TSBAccountInstrumentMovement` 是持仓变动流水表,记录所有证券变动事件\n- `MovementType = 'T'`(Transfer)特指**账户间股票转移**,对应 `TransferToAccountID` 记录目标账户\n- `ValueDate` 是转移生效日期,可按日期过滤\n- 关联 `MCInstrument` 获取证券代码/名称\n- 注意:`BCAccountInstrument` 的 `TodayIn/TodayOut` 是**实时快照**,不带历史日期维度,不能用于查历史转移", "question_en": "List all stock transfers between client accounts performed today.", "rating": 9, "execution_result": null, "result_note": "当前查询无结果(测试环境中 `TSBAccountInstrumentMovement` 的 `MovementType='T'` 最新记录为 2025-10-21,无 2026-04-02 的账户间转移数据)", "tags": ["join", "ordering", "filter", "account", "left_join"], "difficulty": "hard"}
{"qid": "Q3", "question_zh": "今日结算使用的汇率是多少?", "sql": "-- 查询汇率类型列表 (固定日期: 2026-04-02)\nSELECT \n ExchangeRateID, \n Name, \n NameEx\nFROM HCExchangeRate\nWHERE ValueDate = '2026-04-02'\nORDER BY ExchangeRateID;", "schema_info": {"tables": {"HCExchangeRate": {"alias": "HCExchangeRate", "columns": []}}, "joins": []}, "explanation": "- `HCExchangeRate` 存储汇率类型定义\n- `HCExchangeRateDetail` 存储各货币对的汇率值\n- 两个表通过 `ExchangeRateID` + `ValueDate` 关联\n- `ExchangeRateDirection` = 'D' 表示直接汇率", "question_en": "What are the currency exchange rates used for today's settlement?", "rating": 9, "execution_result": null, "result_note": "", "tags": ["exchange_rate", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q4", "question_zh": "哪些券商尚有未履行的交收义务?", "sql": "-- 查询有未履行交收义务的经纪商(截至 2026-04-02)\n-- Settled < 0 表示经纪商欠我们的现金(未履行交收义务)\n-- 注意:BCBrokerCash.Settled 是经纪商在我们账户的已结算现金余额,负数=经纪商欠款\nSELECT \n b.BrokerID,\n m.Name AS BrokerName,\n b.CurrencyID,\n b.Settled AS OwedToUsAmount,\n ABS(b.Settled) AS OutstandingAmount\nFROM BCBrokerCash b\nINNER JOIN MCBroker m ON b.BrokerID = m.BrokerID\nWHERE b.Settled < 0\nORDER BY ABS(b.Settled) DESC;", "schema_info": {"tables": {"BCBrokerCash": {"alias": "b", "columns": []}, "MCBroker": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "b.BrokerID = m.BrokerID"}]}, "explanation": "- `BCBrokerCash` 记录经纪商在我们账户的结算现金,`Settled < 0` = 经纪商欠我们(未履行交收义务)\n- 关联 `MCBroker` 获取经纪商名称\n- 按欠款金额降序排列,优先处理大额欠款", "question_en": "Which brokers have outstanding delivery obligations to us?", "rating": 8, "execution_result": null, "result_note": "| BrokerID | BrokerName | CurrencyID | OwedToUsAmount | OutstandingAmount |\n|----------|-----------|------------|-----------------|-------------------|\n| CCASS | CCASS | CNY | -52,680.00 | 52,680.00 |\n| CCASS | CCASS | USD | -90.00 | 90.00 |\n\n> 注:CCASS 欠我们的结算现金(CNY 52,680 + USD 90)。HKD 余额为正(+4,202,811.87)表示我们欠 CCASS,不属于\"未履行交收义务\"范畴。", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q6", "question_zh": "所有货币的客户现金总余额是多少?", "sql": "-- 按货币统计客户现金余额\nSELECT \n CurrencyID,\n COUNT(DISTINCT AccountID) AS AccountCount,\n SUM(Settled) AS TotalSettledBalance,\n SUM(AccruedCreditInterest) AS TotalCreditInterest,\n SUM(AccruedDebitInterest) AS TotalDebitInterest,\n SUM(Settled) + SUM(AccruedCreditInterest) - SUM(AccruedDebitInterest) AS NetBalance\nFROM BCAccountCash\nGROUP BY CurrencyID\nORDER BY NetBalance DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `BCAccountCash` 记录账户现金余额\n- `Settled` 已结算余额\n- `AccruedCreditInterest` 应计存款利息\n- `AccruedDebitInterest` 应计借款利息", "question_en": "What is the total client cash balance across all currencies?", "rating": 9, "execution_result": null, "result_note": "| CurrencyID | AccountCount | TotalSettledBalance | NetBalance |\n|------------|-------------|--------------------|------------|\n| HKD | 2,906 | 52,195,305.77 | 52,195,305.77 |\n| TWD | 2 | -27,676.60 | -27,676.60 |\n| USD | 175 | 0 | 0 |\n| CNY | 95 | 0 | 0 |\n| GBP | 1 | 0 | 0 |", "tags": ["ordering", "account", "cash", "aggregation"], "difficulty": "medium"}
{"qid": "Q7", "question_zh": "今日结算后现金余额为负的账户列表。", "sql": "-- 查询现金余额为负的账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.CurrencyID,\n c.Settled AS CashBalance,\n c.UnderdueCheque,\n c.BankAvailableBalance\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.Settled < 0\nORDER BY c.Settled ASC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash.Settled` 表示已结算现金余额\n- 负数表示账户透支\n- 关联 `MCAccount` 获取账户名称", "question_en": "List accounts with negative cash balance after today's settlement.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | CurrencyID | CashBalance |\n|-----------|------------|------------|-------------|\n| M050009 | NG SUN SHU*** | HKD | -4,678,978.42 |\n| P050667 | WONG YIM HUNG | HKD | -780,196.94 |\n| M050521 | LO CHUN YIP | HKD | -290,487.54 |\n\n(共55个账户现金余额为负)", "tags": ["join", "ordering", "filter", "account", "cash"], "difficulty": "hard"}
{"qid": "Q8", "question_zh": "明天生效的公司行动涉及哪些证券?", "sql": "-- 查询明日生效的公司行动 (固定日期: 2026-04-03)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.BalanceDate AS EffectiveDate,\n e.BalanceExDate AS ExDate,\n e.Remark AS Description\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE (e.BalanceDate = '2026-04-03' OR e.BalanceExDate = '2026-04-03')\n AND e.State = 'A';", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录权益分派信息\n- `BalanceDate` 权益登记日期\n- `BalanceExDate` 除权日期", "question_en": "Which instruments have corporate actions effective tomorrow?", "rating": 8, "execution_result": null, "result_note": "当前查询无结果(2026-04-03无公司行动)", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q9", "question_zh": "今日预计收到哪些股息?", "sql": "-- 查询今日预计收到的股息 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceDate AS PaymentDate,\n e.BalanceType,\n e.Remark AS DividendDetails\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.BalanceDate = '2026-04-02'\n AND e.BalanceType = 'C'\n AND e.State = 'A'\nORDER BY i.Name;", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录所有权益分派\n- `BalanceType = 'C'` 表示现金股息\n- `BalanceDate` 股息支付日期", "question_en": "What dividends are expected to be received today?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q10", "question_zh": "列出所有进行中IPO的待缴申购金额。", "sql": "-- 查询进行中IPO的待缴金额\nSELECT \n ip.InstrumentID,\n i.Name AS InstrumentName,\n i.State AS InstrumentStatus,\n ip.SubscriptionAmount,\n ip.SubscriptionPrice,\n ip.Quantity AS SubscriptionLot,\n ip.CreatedOn AS SubscriptionDate,\n ip.State AS SubscriptionStatus\nFROM MCInstrumentIPODetail ip\nINNER JOIN MCInstrument i ON ip.InstrumentID = i.InstrumentID\nWHERE ip.State = 'A'\n AND i.State = 'A'\nORDER BY ip.CreatedOn DESC;", "schema_info": {"tables": {"MCInstrumentIPODetail": {"alias": "ip", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "ip.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MCInstrumentIPODetail` 记录IPO认购详情\n- `SubscriptionAmount` 申购金额\n- `State = 'A'` 表示进行中", "question_en": "Show all pending subscription amounts for ongoing IPOs.", "rating": 8, "execution_result": null, "result_note": "| InstrumentID | InstrumentName | SubscriptionAmount | SubscriptionPrice | Quantity |\n|--------------|----------------|-------------------|-------------------|----------|\n| 02259 | HKEX | 7,231.19 | 36.16 | 100 |\n| 02259 | HKEX | 14,462.40 | 36.16 | 200 |\n\n> 注:MCInstrumentIPODetail 共 586 条进行中 IPO 记录(State='A'),以上为示例行。", "tags": ["join", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q20", "question_zh": "哪些公司行动的选择指令需在今日结束前提交?", "sql": "-- 查询今日截止的公司行动选择 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.ElectionPeriodTo AS Deadline,\n e.ElectionOptionFlag,\n e.Remark AS Description\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.ElectionPeriodTo = '2026-04-02'\n AND e.ElectionOptionFlag = 'Y'\n AND e.State = 'A';", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `ElectionPeriodTo` 选择截止日期\n- `ElectionOptionFlag = 'Y'` 需要选择", "question_en": "Which corporate action elections are due by end of day?", "rating": 8, "execution_result": null, "result_note": "当前查询无今日截止的选择", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q21", "question_zh": "截至昨日的客户借方余额应计利息是多少?", "sql": "-- 查询客户借方余额应计利息 (截至2026-04-01)\nSELECT \n SUM(AccruedDebitInterest) AS TotalDebitInterestAccrued,\n SUM(AccruedCreditInterest) AS TotalCreditInterestAccrued,\n SUM(AccruedDebitInterest) - SUM(AccruedCreditInterest) AS NetDebitInterest,\n COUNT(DISTINCT AccountID) AS AccountCount\nFROM BCAccountCash\nWHERE AccruedDebitInterest > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "BCAccountCash", "columns": []}}, "joins": []}, "explanation": "- `AccruedDebitInterest` 借款应计利息\n- `AccruedCreditInterest` 存款应计利息", "question_en": "What is the interest accrued on client debit balances as of yesterday?", "rating": 8, "execution_result": null, "result_note": "| TotalDebitInterestAccrued | TotalCreditInterestAccrued | NetDebitInterest | AccountCount |\n|---------------------------|---------------------------|-----------------|-------------|\n| 2,022.70 | 464.15 | 1,558.55 | 55 |", "tags": ["filter", "account", "interest", "cash", "aggregation"], "difficulty": "hard"}
{"qid": "Q23", "question_zh": "列出所有逾期未付保证金利息的账户。", "sql": "-- 查询逾期保证金利息账户\nSELECT \n c.AccountID,\n a.Name AS AccountName,\n c.LoanInterestMarginOverdue AS MarginOverdueInterest,\n c.LoanInterestMarginBOverdue AS MarginBOverdueInterest,\n c.LoanInterestOverdue AS GeneralOverdueInterest\nFROM BCAccountCash c\nINNER JOIN MCAccount a ON c.AccountID = a.AccountID\nWHERE c.LoanInterestMarginOverdue > 0 \n OR c.LoanInterestMarginBOverdue > 0\n OR c.LoanInterestOverdue > 0\nORDER BY (c.LoanInterestMarginOverdue + c.LoanInterestMarginBOverdue + c.LoanInterestOverdue) DESC;", "schema_info": {"tables": {"BCAccountCash": {"alias": "c", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "c.AccountID = a.AccountID"}]}, "explanation": "- `LoanInterestMarginOverdue` 保证金账户逾期利息\n- `LoanInterestMarginBOverdue` B类保证金逾期利息", "question_en": "Show all accounts with overdue margin interest payments.", "rating": 8, "execution_result": null, "result_note": "当前查询无逾期利息记录", "tags": ["join", "ordering", "margin", "filter", "account", "interest"], "difficulty": "hard"}
{"qid": "Q26", "question_zh": "本月各交易所的结算费用明细如何?", "sql": "-- 按交易所统计结算费用 (2026年4月)\n-- 说明:BCAccountInstrument 表中 TotalBoughtFee/TotalSoldFee 是持仓级别的交易费用字段\n-- LastTransactionDate 表示该持仓最后交易日期\n-- 查询逻辑:筛选最后交易日期在本月内的持仓记录,按交易所汇总交易费用\nSELECT \n bi.MarketID,\n m.MarketName,\n SUM(bi.TotalBoughtFee) AS TotalBuyFee,\n SUM(bi.TotalSoldFee) AS TotalSellFee,\n SUM(bi.TotalBoughtFee + bi.TotalSoldFee) AS TotalSettlementFee,\n COUNT(DISTINCT bi.AccountID) AS TradingAccountCount\nFROM BCAccountInstrument bi\nINNER JOIN MCMarket m ON bi.MarketID = m.MarketID\nWHERE bi.LastTransactionDate >= '2026-04-01' AND bi.LastTransactionDate < '2026-05-01'\nGROUP BY bi.MarketID, m.MarketName\nORDER BY TotalSettlementFee DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "bi", "columns": []}, "MCMarket": {"alias": "m", "columns": []}}, "joins": [{"type": "INNER", "on": "bi.MarketID = m.MarketID"}]}, "explanation": "- `BCAccountInstrument` 存储持仓级别信息,包含各持仓的交易费用累计\n- `MCMarket` 存储市场信息,提供市场名称\n- `LastTransactionDate` 用于过滤本月有交易的持仓记录\n- 按市场分组汇总结算费用", "question_en": "What is the breakdown of settlement fees by exchange for this month?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "ordering", "filter", "trade", "aggregation", "date_range"], "difficulty": "hard"}
{"qid": "Q27", "question_zh": "列出所有超过3天的暂记账户分录。", "sql": "-- 查询超过3天的暂记账户分录 (2026-04-02)\n-- 说明:TCAccountCashMovement 是现金流水表\n-- NeedHoldFlag='Y' 表示暂记分录\n-- Amount - ReleasedAmount 表示未释放金额(暂记余额)\n-- 筛选未释放且超过3天的暂记分录\nSELECT \n cm.AccountID,\n cm.MovementID,\n cm.ValueDate,\n cm.CurrencyID,\n cm.Amount - ISNULL(cm.ReleasedAmount, 0) AS PendingBalance,\n cm.Remark,\n DATEDIFF(DAY, cm.ValueDate, '2026-04-02') AS DaysOutstanding\nFROM TCAccountCashMovement cm\nWHERE cm.NeedHoldFlag = 'Y'\n AND cm.Amount - ISNULL(cm.ReleasedAmount, 0) != 0\n AND DATEDIFF(DAY, cm.ValueDate, '2026-04-02') > 3\nORDER BY DaysOutstanding DESC, PendingBalance DESC;", "schema_info": {"tables": {"TCAccountCashMovement": {"alias": "cm", "columns": []}}, "joins": []}, "explanation": "- `TCAccountCashMovement` 存储现金流水记录\n- `NeedHoldFlag = 'Y'` 标识暂记(待确认)分录\n- `Amount - ReleasedAmount` 计算未释放的暂记余额\n- `DATEDIFF` 计算距今天数\n- `DATEDIFF > 3` 筛选超过3天的记录", "question_en": "List all suspense account entries older than 3 days.", "rating": 9, "execution_result": null, "result_note": "**查询结果:0条记录**\n\n当前没有超过3天未释放的暂记账户分录。所有暂记分录的 ReleasedAmount = Amount,已全部释放。", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q29", "question_zh": "列出后台系统中所有活跃用户账户及其最后登录日期。", "sql": "-- 查询活跃用户及其登录情况\nSELECT \n u.UserID,\n u.Name AS UserName,\n u.Status,\n u.LogonEnableFlag,\n u.LastLogonTime,\n u.BranchID,\n CASE u.CompanyAEFlag WHEN 'Y' THEN '公司经纪' ELSE '个人' END AS AEType,\n CASE \n WHEN u.LastLogonTime >= DATEADD(DAY, -7, GETDATE()) THEN '近7天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -30, GETDATE()) THEN '近30天活跃'\n WHEN u.LastLogonTime >= DATEADD(DAY, -90, GETDATE()) THEN '近90天活跃'\n ELSE '长期未登录'\n END AS ActivityStatus\nFROM MCUser u\nWHERE u.State = 'A'\n AND u.LogonEnableFlag = 'Y'\nORDER BY u.LastLogonTime DESC;", "schema_info": {"tables": {"MCUser": {"alias": "u", "columns": []}}, "joins": []}, "explanation": "- `MCUser` 存储用户信息\n- `LastLogonTime` 最后登录时间", "question_en": "List all active user accounts in the back office system with last login date.", "rating": 9, "execution_result": null, "result_note": "| UserID | UserName | Status | LogonEnableFlag | LastLogonTime | ActivityStatus |\n|--------|----------|--------|-----------------|---------------|----------------|\n| SUPPORT | SUPPORT | N | Y | 2026-04-08 | 近7天活跃 |\n| ROSANNA | ROSANNA | N | Y | 2025-10-21 | 长期未登录 |\n| SING | WONG LO SING | N | Y | 2025-10-21 | 长期未登录 |\n| LEONNG | LEON NG | N | Y | 2025-10-21 | 长期未登录 |", "tags": ["account", "date_function", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q30", "question_zh": "按结算日期划分的未结算交易总风险敞口是多少?", "sql": "-- 按结算日期分组的未结算交易敞口\nSELECT \n SettlementType,\n SUM(Amount) AS TotalExposure\nFROM (\n SELECT 'DueBuy_T1' AS SettlementType, SUM(DueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'DueSell_T1' AS SettlementType, SUM(DueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueBuy' AS SettlementType, SUM(NextDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextDayDueSell' AS SettlementType, SUM(NextDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueBuy' AS SettlementType, SUM(NextTwoDayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'NextTwoDayDueSell' AS SettlementType, SUM(NextTwoDayDueSell) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueBuy' AS SettlementType, SUM(TodayDueBuy) AS Amount FROM BCAccountInstrument\n UNION ALL\n SELECT 'TodayDueSell' AS SettlementType, SUM(TodayDueSell) AS Amount FROM BCAccountInstrument\n) t\nGROUP BY SettlementType\nORDER BY SettlementType;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表包含所有账户的证券持仓和交收信息\n- `DueBuy/DueSell` 表示T+1到期的买卖数量", "question_en": "What is the total exposure from unsettled trades by settlement date?", "rating": 8, "execution_result": null, "result_note": "| SettlementType | TotalExposure |\n|----------------|---------------|\n| DueBuy_T1 | 0 |\n| DueSell_T1 | 0 |\n| NextDayDueBuy | 0 |\n| NextDayDueSell | 0 |\n| NextTwoDayDueBuy | 0 |\n| NextTwoDayDueSell | 0 |\n| TodayDueBuy | 1,800 |\n| TodayDueSell | 1,000 |\n\n**注:** `DueBuy/DueSell` 等字段表示应交收数量(T+1/T+2/今日),非金额敞口。如需金额敞口,需乘以价格。", "tags": ["union", "trade", "ordering", "aggregation"], "difficulty": "hard"}
{"qid": "Q31", "question_zh": "指定日期或日期范围内收到的交易量(如成交金额)及相应佣金是多少?", "sql": "-- 交易量和佣金统计\nSELECT \n SUM(TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(TotalBoughtFee) AS TotalBuyCommission,\n SUM(TotalSoldConsideration) AS TotalSellConsideration,\n SUM(TotalSoldFee) AS TotalSellCommission,\n SUM(TotalBoughtConsideration) + SUM(TotalSoldConsideration) AS TotalConsideration,\n SUM(TotalBoughtFee) + SUM(TotalSoldFee) AS TotalCommission\nFROM BCAccountInstrument;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表记录了账户所有历史买卖交易\n- `TotalBoughtConsideration / TotalSoldConsideration`: 买卖成交金额", "question_en": "What is the trading volume (e.g., consideration) and corresponding commission amount received for a specific date or date range?", "rating": 9, "execution_result": null, "result_note": "| TotalBuyConsideration | TotalBuyCommission | TotalSellConsideration | TotalSellCommission | TotalConsideration | TotalCommission |\n|---------------------|-------------------|----------------------|--------------------|-------------------|-----------------|\n| 945,480,833.78 | 793,149.07 | 278,693,891.64 | 809,248.89 | 1,224,174,725.42 | 1,602,397.96 |", "tags": ["trade", "aggregation"], "difficulty": "easy"}
{"qid": "Q32", "question_zh": "各市场客户不同资产(如股票、债券、基金、虚拟资产)的总持仓是多少?", "sql": "-- 按市场统计客户持仓\nSELECT \n b.MarketID,\n COUNT(DISTINCT b.AccountID) AS AccountCount,\n SUM(b.Settled) AS TotalQuantity,\n SUM(b.CostAmount) AS TotalCostAmount,\n SUM(b.TotalBoughtQuantity) AS TotalBoughtQty,\n SUM(b.TotalSoldQuantity) AS TotalSoldQty\nFROM BCAccountInstrument b\nGROUP BY b.MarketID\nORDER BY TotalCostAmount DESC;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "b", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 表记录账户在各市场的持仓\n- `MarketID` 区分不同市场", "question_en": "What is the total client holding of different assets (e.g., stocks, bonds, funds, virtual assets) by each market?", "rating": 8, "execution_result": null, "result_note": "| MarketID | AccountCount | TotalQuantity | TotalCostAmount | TotalBoughtQty | TotalSoldQty |\n|----------|-------------|---------------|-----------------|---------------|-------------|\n| HKEX | 2,102 | 717,471,548 | 87,813,213.45 | 1,015,923,906 | 298,452,798 |\n| SETW | 2 | 3,100 | 32,298.50 | 4,100 | 1,000 |", "tags": ["account", "holding", "ordering", "aggregation"], "difficulty": "medium"}
{"qid": "Q33", "question_zh": "今日是否有追缴保证金通知?", "sql": "-- 查询今日追缴保证金记录 (固定日期: 2026-04-02)\nSELECT \n m.AccountID,\n a.Name AS AccountName,\n m.CallForDeposit,\n m.CallForDepositDate,\n m.CallForDepositDays\nFROM HCAccountMarginCallForDeposit m\nINNER JOIN MCAccount a ON m.AccountID = a.AccountID\nWHERE m.CallForDepositDate = '2026-04-02';", "schema_info": {"tables": {"HCAccountMarginCallForDeposit": {"alias": "m", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "m.AccountID = a.AccountID"}]}, "explanation": "- `HCAccountMarginCallForDeposit` 记录追缴保证金信息\n- `CallForDeposit` 追缴金额", "question_en": "Have there been any margin calls today?", "rating": 9, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "margin", "filter"], "difficulty": "easy"}
{"qid": "Q34", "question_zh": "保证金账户前20大持仓(按市值)是多少?", "sql": "-- 保证金账户按市值排序的前20持仓\nSELECT TOP 20\n a.AccountID,\n a.Name AS AccountName,\n a.MarketValue,\n a.MarginDebitRatio AS MarginDebitBalanceRatio,\n a.MarginPosition,\n a.CallForDeposit,\n a.MarginFacilityFlag\nFROM MCAccount a\nWHERE a.MarginFacilityFlag = 'Y'\n AND a.State = 'A'\n AND a.MarketValue > 0\nORDER BY a.MarketValue DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 表包含所有账户信息\n- `MarginFacilityFlag = 'Y'` 筛选保证金账户", "question_en": "What are the top 20 holdings (based on market value) for margin accounts?", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginPosition |\n|-----------|-------------|------------|----------------|\n| M050009 | NG SUN SHU*** | 57,420,000 | 35,515,021.58 |\n| M050013 | NG CHUNG WAI*** | 19,504,520 | 10,918,958.78 |\n| M050193 | WONG KING YIU*** ^ | 11,682,920 | 3,340,099.05 |\n| P020160 | LAW SHIU MING DENNIS | 7,520,370 | 0 |\n| P030078 | MAK SUI BING | 7,120,309.94 | 0 |\n| P051101 | CHUNG CHUNG YEE | 7,117,808.04 | 0 |\n| M050170 | FUNG LAI FONG ANNA | 7,009,227.25 | 4,136,857 |\n| P220005 | LAI KAM SUI # | 5,837,102.10 | 97.97 |\n| P280628 | CHAN KWOK MO # | 5,761,997.48 | 62,508.23 |\n| P280455 | LEUNG KA CHI # | 5,487,971.20 | -64,981.22 |\n\n(共20条记录,以上展示前10条)", "tags": ["ordering", "holding", "margin", "filter", "limit", "account"], "difficulty": "hard"}
{"qid": "Q35", "question_zh": "列出本月按客户主任分组的佣金总额,以及相应的成交金额和返佣金额。", "sql": "-- 按经纪商/客户主任分组的佣金统计\nSELECT \n a.AEID,\n u.Name AS AEName,\n COUNT(DISTINCT a.AccountID) AS AccountCount,\n SUM(bi.TotalBoughtFee) AS TotalBuyCommission,\n SUM(bi.TotalSoldFee) AS TotalSellCommission,\n SUM(bi.TotalBoughtConsideration) AS TotalBuyConsideration,\n SUM(bi.TotalSoldConsideration) AS TotalSellConsideration,\n SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) AS TotalCommission\nFROM MCAccount a\nLEFT JOIN MCUser u ON a.AEID = u.UserID\nLEFT JOIN BCAccountInstrument bi ON a.AccountID = bi.AccountID\nWHERE a.State = 'A'\nGROUP BY a.AEID, u.Name\nHAVING SUM(bi.TotalBoughtFee) + SUM(bi.TotalSoldFee) > 0\nORDER BY TotalCommission DESC;", "schema_info": {"tables": {"MCAccount": {"alias": "a", "columns": []}, "MCUser": {"alias": "u", "columns": []}, "BCAccountInstrument": {"alias": "bi", "columns": []}}, "joins": [{"type": "LEFT", "on": "a.AEID = u.UserID"}, {"type": "LEFT", "on": "a.AccountID = bi.AccountID"}]}, "explanation": "- `MCAccount.AEID` 关联经纪商/客户主任\n- `BCAccountInstrument` 包含交易费用数据", "question_en": "List the total commission received this month by AE, along with corresponding consideration and rebate amounts.", "rating": 8, "execution_result": null, "result_note": "| AEID | AEName | AccountCount | TotalBuyCommission | TotalSellCommission | TotalCommission |\n|------|--------|-------------|-------------------|--------------------|----------------|\n| C01 | CHAN YUET HUNG | 628 | 183,244.64 | 187,220.59 | 370,465.23 |\n| C28 | CHAN SHU SHAN | 405 | 179,275.89 | 176,760.39 | 356,036.28 |\n| C05 | CENTRAL | 517 | 97,368.51 | 102,819.88 | 200,188.39 |\n| C33 | LEON NG | 13 | 71,541.06 | 72,620.60 | 144,161.66 |\n| C07 | CHAN WING PAI | 75 | 73,255.68 | 69,115.58 | 142,371.26 |\n| C10 | TOKWAWAN / KOWLOON CITY | 369 | 51,059.78 | 57,288.86 | 108,348.64 |\n| C08 | WONG HON KONG | 380 | 47,505.15 | 46,300.39 | 93,805.54 |\n| C36 | Name Of C36 | 146 | 40,945.66 | 35,682.86 | 76,628.52 |\n| C66 | CHEUNG YUK LING IVA | 17 | 24,458.82 | 22,723.18 | 47,182.00 |\n| C19 | WONG LO SING | 60 | 13,337.69 | 13,912.30 | 27,249.99 |\n\n(共15个AE有佣金记录,以上展示前10条)\n\n**注:** 当前SQL无日期条件,统计所有历史累计佣金。如需\"本月\"佣金,需添加 `LastTransactionDate >= '2026-04-01'` 条件。", "tags": ["join", "ordering", "filter", "account", "left_join", "aggregation"], "difficulty": "hard"}
{"qid": "Q37", "question_zh": "是否有正在进行的IPO事件,其认购状态如何?", "sql": "-- 查询进行中的IPO (2026年4月)\nSELECT \n i.InstrumentID,\n i.MarketID,\n i.Name AS InstrumentName,\n i.State AS InstrumentStatus,\n ip.Quantity AS SubscriptionLot,\n ip.SubscriptionAmount,\n ip.CreatedOn AS SubscriptionDate\nFROM MCInstrument i\nINNER JOIN MCInstrumentIPODetail ip ON i.InstrumentID = ip.InstrumentID\nWHERE YEAR(ip.CreatedOn) = 2026\n AND MONTH(ip.CreatedOn) = 4\nORDER BY ip.CreatedOn DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "i", "columns": []}, "MCInstrumentIPODetail": {"alias": "ip", "columns": []}}, "joins": [{"type": "INNER", "on": "i.InstrumentID = ip.InstrumentID"}]}, "explanation": "- `MCInstrument` 表记录证券信息\n- `MCInstrumentIPODetail` 记录IPO认购详情", "question_en": "Are there any IPO events currently in progress, and what is their subscription status?", "rating": 8, "execution_result": null, "result_note": "", "tags": ["join", "filter", "ipo", "ordering"], "difficulty": "easy"}
{"qid": "Q39", "question_zh": "列出今日需要执行的公司行动(如权益分派)。", "sql": "-- 查询今日生效的公司行动 (固定日期: 2026-04-02)\nSELECT \n e.EntitlementID,\n e.MarketID,\n e.InstrumentID,\n i.Name AS InstrumentName,\n e.BalanceType,\n e.BalanceDate,\n e.BalanceExDate,\n e.Remark,\n e.State\nFROM MSBEntitlement e\nINNER JOIN MCInstrument i ON e.InstrumentID = i.InstrumentID\nWHERE e.State = 'A'\n AND (\n e.BalanceDate = '2026-04-02'\n OR e.BalanceExDate = '2026-04-02'\n OR e.AutoHoldDate = '2026-04-02'\n OR e.AutoDeductDate = '2026-04-02'\n );", "schema_info": {"tables": {"MSBEntitlement": {"alias": "e", "columns": []}, "MCInstrument": {"alias": "i", "columns": []}}, "joins": [{"type": "INNER", "on": "e.InstrumentID = i.InstrumentID"}]}, "explanation": "- `MSBEntitlement` 记录所有权益分派信息\n- `BalanceDate` 权益登记日期", "question_en": "List corporate actions (e.g., entitlements) that need to be performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "filter", "corporate_action"], "difficulty": "easy"}
{"qid": "Q40", "question_zh": "列出今日执行的所有股票转移/移动。", "sql": "-- 今日股票转入/转出 (固定日期: 2026-04-02)\nSELECT \n AccountID,\n MarketID,\n InstrumentID,\n TodayIn AS QuantityIn,\n TodayOut AS QuantityOut,\n HoldForDeposit AS PendingDeposit,\n HoldForWithdrawal AS PendingWithdrawal\nFROM BCAccountInstrument\nWHERE TodayIn > 0 OR TodayOut > 0;", "schema_info": {"tables": {"BCAccountInstrument": {"alias": "BCAccountInstrument", "columns": []}}, "joins": []}, "explanation": "- `BCAccountInstrument` 记录股票持仓变动\n- `TodayIn` 今日转入数量", "question_en": "List all stock movements performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["filter"], "difficulty": "easy"}
{"qid": "Q41", "question_zh": "列出今日执行的所有现金划转。", "sql": "-- 今日现金变动汇总 (固定日期: 2026-04-02)\nSELECT \n b.AccountID,\n a.Name AS AccountName,\n b.TodayIn AS CashIn,\n b.TodayOut AS CashOut,\n b.BankAvailableBalance\nFROM BCAccountCash b\nINNER JOIN MCAccount a ON b.AccountID = a.AccountID\nWHERE b.TodayIn > 0 OR b.TodayOut > 0;", "schema_info": {"tables": {"BCAccountCash": {"alias": "b", "columns": []}, "MCAccount": {"alias": "a", "columns": []}}, "joins": [{"type": "INNER", "on": "b.AccountID = a.AccountID"}]}, "explanation": "- `BCAccountCash` 记录账户现金变动\n- `TodayIn` 今日现金流入", "question_en": "List all cash movements performed today.", "rating": 8, "execution_result": null, "result_note": "当前查询无结果", "tags": ["join", "filter", "cash"], "difficulty": "easy"}
{"qid": "Q42", "question_zh": "列出后台系统中的活跃用户。", "sql": "-- 查询后台系统活跃用户\nSELECT \n u.UserID,\n u.Name AS UserName,\n u.Status,\n u.LogonEnableFlag,\n u.LastLogonTime,\n u.BranchID,\n u.DepartmentID,\n CASE u.CompanyAEFlag WHEN 'Y' THEN '公司经纪' ELSE '个人' END AS AEType\nFROM MCUser u\nWHERE u.State = 'A'\n AND u.LogonEnableFlag = 'Y'\nORDER BY u.LastLogonTime DESC;", "schema_info": {"tables": {"MCUser": {"alias": "u", "columns": []}}, "joins": []}, "explanation": "- `MCUser` 存储系统用户信息\n- `State = 'A'` 用户状态正常", "question_en": "List active users in the back office.", "rating": 9, "execution_result": null, "result_note": "| UserID | UserName | Status | LogonEnableFlag | LastLogonTime | AEType |\n|--------|----------|--------|-----------------|---------------|--------|\n| SUPPORT | SUPPORT | N | Y | 2026-04-03 18:53:04 | 个人 |\n| ROSANNA | ROSANNA | N | Y | 2025-10-21 16:47:11 | 个人 |", "tags": ["filter", "ordering"], "difficulty": "easy"}
{"qid": "Q43", "question_zh": "列出持仓为负数(透支)的账户。", "sql": "-- 查询透支持仓账户\nSELECT \n AccountID,\n Name AS AccountName,\n MarketValue,\n AssetBalance,\n LiabilityBalance,\n MarginPosition,\n MarginFacilityFlag\nFROM MCAccount\nWHERE MarketValue < 0\n AND State = 'A'\nORDER BY MarketValue ASC;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MarketValue < 0` 筛选持仓为负的账户\n- 持仓为负通常表示账户存在透支或结算问题", "question_en": "List accounts with overdrawn positions.", "rating": 9, "execution_result": null, "result_note": "| AccountID | AccountName | MarketValue | MarginFacilityFlag |\n|-----------|-------------|-------------|-------------------|\n| P030012 | LAI YEE TAK HELEN | -112,196.60 | N |\n| P350022 | CHAN YAU KING*** | -92,950.00 | N |\n| P011212 | NG SIU PING | -12,352.00 | N |", "tags": ["account", "holding", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q47", "question_zh": "今日/指定日期发放了多少份日结单或月结单?", "sql": "-- 查询报表发放统计 (2026-04-02)\nSELECT \n 'Daily Statement' AS StatementType,\n COUNT(*) AS StatementCount\nFROM MCAccount\nWHERE LastDailyStatementDate = '2026-04-02'\nUNION ALL\nSELECT \n 'Monthly Statement' AS StatementType,\n COUNT(*) AS StatementCount\nFROM MCAccount\nWHERE LastMonthlyStatementDate = '2026-04-02';", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount` 记录账户报表发送日期\n- `LastDailyStatementDate` 最近日结单发送日期", "question_en": "How many daily or monthly statements were issued today / on a specific date?", "rating": 9, "execution_result": null, "result_note": "", "tags": ["union", "filter", "aggregation"], "difficulty": "hard"}
{"qid": "Q48", "question_zh": "列出所有支持保证金的证券及其相应的保证金比例。", "sql": "-- 查询支持保证金的证券\nSELECT \n InstrumentID,\n Name AS InstrumentName,\n MarginPercentage AS MarginRatio,\n CASE \n WHEN MarginPercentage >= 0.7 THEN '高'\n WHEN MarginPercentage >= 0.5 THEN '中'\n WHEN MarginPercentage > 0 THEN '低'\n ELSE 'N/A'\n END AS RiskLevel,\n MarginLimitPerInstrument,\n CollateralRatio\nFROM MCInstrument\nWHERE MarginPercentage IS NOT NULL\n AND MarginPercentage > 0\n AND State = 'A'\nORDER BY MarginPercentage DESC;", "schema_info": {"tables": {"MCInstrument": {"alias": "MCInstrument", "columns": []}}, "joins": []}, "explanation": "- `MCInstrument` 存储证券信息\n- `MarginPercentage` 保证金比例", "question_en": "List all instruments that support margin and their corresponding margin ratios.", "rating": 9, "execution_result": null, "result_note": "| InstrumentID | InstrumentName | MarginRatio | RiskLevel |\n|-------------|----------------|-------------|-----------|\n| 00001 | CKH HOLDINGS(S) | 0.70 | 高 |\n| 00002 | CLP HOLDINGS(S) | 0.70 | 高 |\n| 00003 | HK & CHINA GAS(S) | 0.70 | 高 |\n\n(共767条记录)", "tags": ["margin", "limit", "filter", "ordering"], "difficulty": "easy"}
{"qid": "Q49", "question_zh": "本月、本季度和今年分别开了多少账户?", "sql": "-- 开户统计 (2026年4月)\nSELECT \n COUNT(CASE WHEN MONTH(OpenDate) = 4 AND YEAR(OpenDate) = 2026 THEN 1 END) AS April2026,\n COUNT(CASE WHEN DATEPART(QUARTER, OpenDate) = 2 AND YEAR(OpenDate) = 2026 THEN 1 END) AS Q2_2026,\n COUNT(CASE WHEN YEAR(OpenDate) = 2026 THEN 1 END) AS Year2026,\n COUNT(*) AS TotalAccounts,\n MIN(OpenDate) AS EarliestOpenDate,\n MAX(OpenDate) AS LatestOpenDate\nFROM MCAccount\nWHERE OpenDate IS NOT NULL;", "schema_info": {"tables": {"MCAccount": {"alias": "MCAccount", "columns": []}}, "joins": []}, "explanation": "- `MCAccount.OpenDate` 账户开户日期\n- 按月、季度、年分别统计新开户数量", "question_en": "How many accounts were opened this month, this quarter, and this year?", "rating": 9, "execution_result": null, "result_note": "| April2026 | Q2_2026 | Year2026 | TotalAccounts | EarliestOpenDate | LatestOpenDate |\n|-----------|---------|----------|---------------|------------------|----------------|\n| 0 | 0 | 0 | 1,951 | 1993-03-05 | 2025-10-16 |", "tags": ["account", "limit", "filter", "aggregation"], "difficulty": "easy"}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
# llm 包初始化
Binary file not shown.
Binary file not shown.
+304
View File
@@ -0,0 +1,304 @@
"""
DeepSeek API 客户端封装
支持同步/异步调用,与CAMEL AI兼容
"""
import os
import json
import logging
from typing import Dict, List, Optional, Any, Union
from dataclasses import dataclass, field
from openai import OpenAI, AsyncOpenAI
from openai.types.chat import ChatCompletion, ChatCompletionMessage
logger = logging.getLogger(__name__)
@dataclass
class DeepSeekConfig:
"""DeepSeek API配置"""
api_key: str
base_url: str = "https://api.deepseek.com"
model_name: str = "deepseek-chat"
temperature: float = 0.3
max_tokens: int = 4096
top_p: float = 0.9
frequency_penalty: float = 0.0
presence_penalty: float = 0.0
timeout: float = 60.0
extra_headers: Optional[Dict[str, str]] = None
class DeepSeekClient:
"""
DeepSeek API 客户端(同步)
使用 OpenAI 兼容接口调用 DeepSeek 模型
"""
def __init__(self, config: DeepSeekConfig):
self.config = config
# 初始化OpenAI客户端(DeepSeek兼容OpenAI协议)
self.client = OpenAI(
api_key=config.api_key,
base_url=config.base_url,
timeout=config.timeout,
)
logger.info(
f"[OK] DeepSeekClient初始化: model={config.model_name}, "
f"base_url={config.base_url}"
)
def chat(
self,
messages: List[Dict[str, str]],
**kwargs
) -> ChatCompletionMessage:
"""
发送聊天请求
Args:
messages: 消息列表,格式为 [{"role": "user", "content": "..."}, ...]
**kwargs: 覆盖默认参数的额外参数
Returns:
ChatCompletionMessage对象(包含.role和.content属性)
"""
# 合并参数
params = {
"model": self.config.model_name,
"messages": messages,
"temperature": kwargs.get("temperature", self.config.temperature),
"max_tokens": kwargs.get("max_tokens", self.config.max_tokens),
"top_p": kwargs.get("top_p", self.config.top_p),
"frequency_penalty": kwargs.get(
"frequency_penalty", self.config.frequency_penalty
),
"presence_penalty": kwargs.get(
"presence_penalty", self.config.presence_penalty
),
"timeout": kwargs.get("timeout", self.config.timeout),
}
if self.config.extra_headers:
params["extra_headers"] = self.config.extra_headers
try:
response: ChatCompletion = self.client.chat.completions.create(**params)
message = response.choices[0].message
# 记录使用情况
usage = response.usage
logger.debug(
f"DeepSeek调用完成: "
f"prompt_tokens={usage.prompt_tokens}, "
f"completion_tokens={usage.completion_tokens}, "
f"total_tokens={usage.total_tokens}"
)
return message
except Exception as e:
logger.error(f"DeepSeek API调用失败: {e}")
raise
def chat_with_json(
self,
messages: List[Dict[str, str]],
**kwargs
) -> Dict[str, Any]:
"""
发送聊天请求并期望JSON格式返回
Args:
messages: 消息列表
**kwargs: 额外参数
Returns:
解析后的JSON字典
"""
message = self.chat(messages, **kwargs)
content = message.content.strip()
try:
# 尝试解析JSON(可能包含markdown代码块)
if "```json" in content:
# 提取```json```之间的内容
start = content.find("```json") + 7
end = content.find("```", start)
content = content[start:end].strip()
elif "```" in content:
# 仅```包裹
start = content.find("```") + 3
end = content.find("```", start)
content = content[start:end].strip()
return json.loads(content)
except json.JSONDecodeError as e:
logger.warning(f"JSON解析失败,返回原始内容: {e}")
return {"raw_content": content}
def generate_sql(
self,
prompt: str,
schema: str,
dialect: str = "tsql",
**kwargs
) -> str:
"""
便捷方法:生成SQL
Args:
prompt: 用户问题
schema: Schema描述
dialect: SQL方言(默认 T-SQL / SQL Server)
**kwargs: 额外参数
Returns:
SQL字符串
"""
from config.prompts import SQL_GENERATOR_SYSTEM, SQL_GENERATOR_USER
messages = [
{"role": "system", "content": SQL_GENERATOR_SYSTEM},
{
"role": "user",
"content": SQL_GENERATOR_USER.format(
schema=schema,
question=prompt,
dialect=dialect
)
}
]
response = self.chat(messages, **kwargs)
content = response.content.strip()
# 提取SQL(移除可能的markdown代码块标记)
if "```sql" in content:
start = content.find("```sql") + 6
end = content.find("```", start)
content = content[start:end].strip()
elif "```" in content:
# 通用代码块
start = content.find("```") + 3
end = content.find("```", start)
content = content[start:end].strip()
return content
def validate_sql(
self,
sql: str,
schema: str,
**kwargs
) -> Dict[str, Any]:
"""
便捷方法:验证SQL
Args:
sql: SQL语句
schema: Schema描述
**kwargs: 额外参数
Returns:
验证结果字典
"""
from config.prompts import VALIDATOR_SYSTEM, VALIDATOR_USER
messages = [
{"role": "system", "content": VALIDATOR_SYSTEM},
{
"role": "user",
"content": VALIDATOR_USER.format(sql=sql, schema=schema)
}
]
return self.chat_with_json(messages, **kwargs)
def select_tables(
self,
question: str,
table_list: str,
**kwargs
) -> Dict[str, Any]:
"""
便捷方法:选择相关表
Args:
question: 用户问题
table_list: 可用表列表字符串
**kwargs: 额外参数
Returns:
包含relevant_tables和reasoning的字典
"""
from config.prompts import SCHEMA_LINKER_SYSTEM, SCHEMA_LINKER_USER
messages = [
{"role": "system", "content": SCHEMA_LINKER_SYSTEM},
{
"role": "user",
"content": SCHEMA_LINKER_USER.format(
question=question,
table_list=table_list
)
}
]
return self.chat_with_json(messages, **kwargs)
class AsyncDeepSeekClient:
"""
DeepSeek API 客户端(异步)
注意:CAMEL AI当前版本主要支持同步Agent,
异步客户端适用于自定义异步流程。
"""
def __init__(self, config: DeepSeekConfig):
self.config = config
self.client = AsyncOpenAI(
api_key=config.api_key,
base_url=config.base_url,
timeout=config.timeout,
)
async def chat(self, messages: List[Dict[str, str]], **kwargs) -> ChatCompletionMessage:
params = {
"model": self.config.model_name,
"messages": messages,
"temperature": kwargs.get("temperature", self.config.temperature),
"max_tokens": kwargs.get("max_tokens", self.config.max_tokens),
}
response = await self.client.chat.completions.create(**params)
return response.choices[0].message
# 便捷工厂函数
def create_deepseek_client(
api_key: Optional[str] = None,
**kwargs
) -> DeepSeekClient:
"""
创建DeepSeek客户端
Args:
api_key: API密钥(可从环境变量DEEPSEEK_API_KEY读取)
**kwargs: 覆盖默认配置的参数
Returns:
DeepSeekClient实例
"""
if api_key is None:
api_key = os.getenv("DEEPSEEK_API_KEY")
if not api_key:
raise ValueError(
"未提供api_key且环境变量DEEPSEEK_API_KEY未设置。"
)
config = DeepSeekConfig(api_key=api_key, **kwargs)
return DeepSeekClient(config)
+406
View File
@@ -0,0 +1,406 @@
#!/usr/bin/env python3
"""
Text2SQL 多智能体系统 - CLI演示入口
用法:
python main.py "查询2024年1月销售额最高的前5个产品"
python main.py --question "查询所有状态为Active的账户数量"
python main.py --interactive # 交互式模式
"""
import os
import sys
import argparse
import logging
from pathlib import Path
from typing import Optional
from dotenv import load_dotenv
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger(__name__)
_DEFAULT_EMBEDDING_PATH = "./data/models/Qwen3-Embedding-0.6B"
def _load_project_env():
"""加载项目根目录 .env(与 main.py 同目录),供后续 os.getenv 使用。"""
load_dotenv(Path(__file__).resolve().parent / ".env")
def _embedding_model_path() -> str:
return os.getenv("EMBEDDING_MODEL_PATH", _DEFAULT_EMBEDDING_PATH).strip()
def resolve_sql_dialect(name: str) -> str:
"""CLI / 配置中的方言别名统一为 sqlglot 方言名(SQL Server -> tsql)。"""
n = (name or "sqlserver").lower().strip()
if n in ("sqlserver", "mssql"):
return "tsql"
return n
def setup_environment():
"""环境检查"""
_load_project_env()
use_local_emb = os.getenv("USE_LOCAL_EMBEDDING", "true").strip().lower() in (
"1", "true", "yes", "on",
)
if use_local_emb:
# 与 .env 中 EMBEDDING_MODEL_PATH 及 utils.embedding 一致
model_path = Path(_embedding_model_path())
if not model_path.exists():
logger.warning(f"Embedding模型不存在: {model_path}")
logger.info("请先下载模型:")
logger.info(" modelscope download --model 'Qwen/Qwen3-Embedding-0.6B' "
f"--local_dir '{model_path}'")
logger.info("或使用远程 Embedding API:USE_LOCAL_EMBEDDING=false,并配置 "
"MODELSCOPE_API_KEY、或 OPENAI_API_KEY+OPENAI_EMBEDDING_MODEL"
"(及可选 OPENAI_BASE_URL)、或 DASHSCOPE_*(百炼)")
return False
else:
ms_key = os.getenv("MODELSCOPE_API_KEY", "").strip()
oa_key = os.getenv("OPENAI_API_KEY", "").strip()
oa_key_ok = oa_key and not (
oa_key.startswith("http://") or oa_key.startswith("https://")
)
if ms_key:
pass # ModelScope:BASE_URL / MODEL 有默认值,仅需 KEY
elif oa_key_ok:
if not os.getenv("OPENAI_EMBEDDING_MODEL", "").strip():
logger.warning("USE_LOCAL_EMBEDDING=false 但未设置 OPENAI_EMBEDDING_MODEL")
return False
else:
if not os.getenv("DASHSCOPE_API_KEY", "").strip():
logger.warning(
"USE_LOCAL_EMBEDDING=false 但未设置 MODELSCOPE_API_KEY、"
"OPENAI_API_KEY+OPENAI_EMBEDDING_MODEL 或 DASHSCOPE_API_KEY"
)
return False
base = (
os.getenv("DASHSCOPE_BASE_URL") or os.getenv("DASHSCOPE_base_url", "")
).strip()
if not base:
logger.warning("未设置 DASHSCOPE_BASE_URL(或 DASHSCOPE_base_url)")
return False
if not os.getenv("DASHSCOPE_MODEL", "").strip():
logger.warning("未设置 DASHSCOPE_MODEL")
return False
# 检查Schema文件
schema_path = Path("./data/schemas/G3SB_MCDataDictionary_table_structure.json")
if not schema_path.exists():
logger.warning(f"Schema文件不存在: {schema_path}")
logger.info("请将G3SB Schema文件放置在 ./data/schemas/ 目录")
return False
# 检查API Key
if not os.getenv("DEEPSEEK_API_KEY"):
logger.warning("环境变量 DEEPSEEK_API_KEY 未设置")
logger.info("请在 .env 文件中配置,或 export DEEPSEEK_API_KEY=your_key")
return False
return True
def _default_g3sb_meta_path(structure_path: str) -> Optional[str]:
"""若存在与 table_structure 同名的 table_meta 文件则返回其路径。"""
p = Path(structure_path)
if "table_structure" not in p.name:
return None
cand = p.parent / p.name.replace("table_structure", "table_meta")
return str(cand) if cand.is_file() else None
def load_schema(schema_path: str, schema_meta_path: Optional[str] = None):
"""加载 Schema;G3SB structure JSON 会自动尝试配对 table_meta(可用 --schema-meta 指定)。"""
from schema.manager import SchemaManager
meta = (
schema_meta_path
if schema_meta_path is not None
else _default_g3sb_meta_path(schema_path)
)
logger.info(f"加载Schema: {schema_path}")
if meta:
logger.info(f" 表注释(meta): {meta}")
schema_mgr = SchemaManager.load_from_json(
schema_path, g3sb_meta_path=meta
)
stats = schema_mgr.get_statistics()
logger.info(
f"[OK] Schema加载完成: {stats['database']}, "
f"共{stats['total_tables']}张表, {stats['total_columns']}个字段"
)
return schema_mgr
def create_orchestrator(schema_mgr, args):
"""创建编排器"""
from agents.orchestrator import Text2SQLOrchestrator
from llm.deepseek_client import DeepSeekConfig
api_key = (args.api_key or os.getenv("DEEPSEEK_API_KEY") or "").strip()
if not api_key:
raise ValueError(
"未配置 DeepSeek API Key:请在 .env 中设置 DEEPSEEK_API_KEY,"
"或使用命令行参数 --api-key"
)
base_url = (os.getenv("DEEPSEEK_BASE_URL") or "https://api.deepseek.com").strip()
config = DeepSeekConfig(
api_key=api_key,
base_url=base_url,
model_name=args.model or "deepseek-chat",
temperature=args.temperature,
max_tokens=args.max_tokens,
)
orchestrator = Text2SQLOrchestrator(
schema_manager=schema_mgr,
deepseek_config=config,
embedding_model_path=args.embedding_model,
vector_db_path=args.vector_db,
max_retry=args.max_retry,
use_vector_search=not args.no_vector_search,
# Few-shot配置
fewshot_enabled=not args.no_fewshot,
fewshot_top_k=args.fewshot_top_k,
fewshot_min_rating=args.fewshot_min_rating,
)
return orchestrator
def single_query(orchestrator, question: str, dialect: str = "tsql"):
"""单次查询"""
import time
logger.info(f"[Q] 问题: {question}")
start = time.time()
result = orchestrator.generate(
question=question,
dialect=dialect,
top_k_candidates=20
)
elapsed = time.time() - start
print("\n" + "=" * 60)
print("生成结果:")
print("=" * 60)
if result.valid:
print(f"[OK] SQL (耗时 {elapsed:.2f}s, 尝试 {result.attempts} 次):\n")
print(result.sql)
else:
print(f"[FAIL] 生成失败 (尝试 {result.attempts} 次)")
for err in result.errors:
print(f" - {err}")
if result.warnings:
print("\n[WARN] 警告:")
for w in result.warnings:
print(f" - {w}")
print(f"\n使用表: {result.tables_used}")
return result
def interactive_mode(orchestrator, dialect: str = "tsql"):
"""交互式模式"""
print("\n" + "=" * 60)
print("Text2SQL 交互模式(输入 'quit' 或 'exit' 退出)")
print("=" * 60 + "\n")
while True:
try:
question = input("❓ 请输入问题: ").strip()
if question.lower() in ('quit', 'exit', 'q'):
print("再见!")
break
if not question:
continue
result = single_query(orchestrator, question, dialect)
print()
except KeyboardInterrupt:
print("\n再见!")
break
except Exception as e:
logger.error(f"查询失败: {e}")
def batch_mode(orchestrator, questions: list, dialect: str = "tsql"):
"""批量查询模式"""
print(f"\n批量模式:共 {len(questions)} 个问题\n")
results = []
for i, question in enumerate(questions, 1):
print(f"[{i}/{len(questions)}] {question}")
result = single_query(orchestrator, question, dialect)
results.append(result)
print()
# 统计
success_count = sum(1 for r in results if r.valid)
print("=" * 60)
print(f"统计: {success_count}/{len(questions)} 成功 "
f"({success_count/len(questions)*100:.1f}%)")
return results
def main():
parser = argparse.ArgumentParser(
description="Text2SQL 多智能体系统 - 自然语言生成SQL"
)
parser.add_argument(
"question",
nargs="?",
help="自然语言问题(如不提供则进入交互模式)"
)
parser.add_argument(
"--schema", "-s",
default="./data/schemas/G3SB_MCDataDictionary_table_structure.json",
help="Schema文件路径(默认: ./data/schemas/G3SB_MCDataDictionary_table_structure.json)"
)
parser.add_argument(
"--schema-meta",
default=None,
help="G3SB table_meta.json;默认自动使用同目录下文件名含 table_meta 的配对文件",
)
parser.add_argument(
"--dialect", "-d",
default=os.getenv("TEXT2SQL_DIALECT", "sqlserver").strip(),
choices=["mysql", "postgresql", "sqlite", "tsql", "sqlserver", "mssql"],
help="SQL方言(默认: sqlserver / T-SQL;可用环境变量 TEXT2SQL_DIALECT 覆盖)",
)
parser.add_argument(
"--api-key",
help="DeepSeek API Key(默认从DEEPSEEK_API_KEY环境变量读取)"
)
parser.add_argument(
"--model", "-m",
default="deepseek-chat",
help="DeepSeek模型名称(默认: deepseek-chat)"
)
parser.add_argument(
"--temperature", "-t",
type=float,
default=0.3,
help="生成温度(默认: 0.3)"
)
parser.add_argument(
"--max-tokens",
type=int,
default=4096,
help="最大token数(默认: 4096)"
)
parser.add_argument(
"--max-retry",
type=int,
default=2,
help="最大重试次数(默认: 2)"
)
_load_project_env()
parser.add_argument(
"--embedding-model",
default=_embedding_model_path(),
help="Embedding模型路径(默认来自环境变量 EMBEDDING_MODEL_PATH)"
)
parser.add_argument(
"--vector-db",
default=os.getenv("VECTOR_DB_PATH", "./data/embeddings/chroma").strip(),
help="向量数据库路径(默认来自环境变量 VECTOR_DB_PATH)"
)
parser.add_argument(
"--no-vector-search",
action="store_true",
help="禁用向量检索(使用所有表)"
)
# Few-shot 配置
parser.add_argument(
"--no-fewshot",
action="store_true",
help="禁用few-shot示例增强"
)
parser.add_argument(
"--fewshot-top-k",
type=int,
default=int(os.getenv("FEWSHOT_TOP_K", "3")),
help="每次使用的few-shot示例数量(默认: 3)"
)
parser.add_argument(
"--fewshot-min-rating",
type=int,
default=int(os.getenv("FEWSHOT_MIN_RATING", "7")),
help="few-shot示例最低评分(默认: 7)"
)
parser.add_argument(
"--interactive", "-i",
action="store_true",
help="交互模式"
)
parser.add_argument(
"--batch", "-b",
help="批量文件路径(每行一个问题)"
)
parser.add_argument(
"--verbose", "-v",
action="store_true",
help="详细日志"
)
args = parser.parse_args()
args.dialect = resolve_sql_dialect(args.dialect)
# 日志级别
if args.verbose:
logging.getLogger().setLevel(logging.DEBUG)
# 环境检查
if not setup_environment():
sys.exit(1)
# 加载Schema
try:
schema_mgr = load_schema(args.schema, args.schema_meta)
except Exception as e:
logger.error(f"Schema加载失败: {e}")
sys.exit(1)
# 创建Orchestrator
try:
orchestrator = create_orchestrator(schema_mgr, args)
except Exception as e:
logger.error(f"Orchestrator创建失败: {e}")
sys.exit(1)
# 根据参数选择模式
if args.interactive or (not args.question and not args.batch):
interactive_mode(orchestrator, args.dialect)
elif args.batch:
with open(args.batch, 'r', encoding='utf-8') as f:
questions = [line.strip() for line in f if line.strip()]
batch_mode(orchestrator, questions, args.dialect)
elif args.question:
single_query(orchestrator, args.question, args.dialect)
else:
parser.print_help()
if __name__ == "__main__":
main()
+120
View File
@@ -0,0 +1,120 @@
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "text2sql-agent-camel"
version = "0.1.0"
description = "Text-to-SQL Multi-Agent System based on CAMEL AI"
readme = "README.md"
requires-python = ">=3.10"
license = {text = "MIT"}
authors = [
{name = "Backman Team"}
]
keywords = ["text2sql", "llm", "agent", "camel-ai", "deepseek"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]
dependencies = [
# CAMEL AI 核心
"camel-ai>=0.2.0",
"camel-ai[all]>=0.2.0", # 包含所有扩展
# LLM API
"openai>=1.0.0",
# 向量数据库
"chromadb>=0.4.0",
# Embedding 模型
"transformers>=4.36.0",
"torch>=2.0.0",
"sentencepiece>=0.1.99",
"accelerate>=0.20.0",
"safetensors>=0.4.0",
# SQL 处理
"sqlglot>=20.0.0",
"sqlparse>=0.4.0",
# 配置与验证
"pydantic>=2.0.0",
"pydantic-settings>=2.0.0",
"python-dotenv>=1.0.0",
# 工具库
"tenacity>=8.0.0",
"structlog>=23.0.0",
"tqdm>=4.65.0",
# 中文分词(可选,用于关键词提取)
"jieba>=0.42.0",
"numpy>=1.24.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.0.0",
"pytest-asyncio>=0.21.0",
"pytest-cov>=4.0.0",
"black>=23.0.0",
"isort>=5.12.0",
"mypy>=1.0.0",
"ruff>=0.1.0",
]
docs = [
"sphinx>=7.0.0",
"sphinx-rtd-theme>=1.3.0",
]
[project.scripts]
text2sql = "text2sql_agent_camel.main:main"
[tool.setuptools.packages.find]
where = ["."]
include = ["text2sql_agent_camel*"]
[tool.black]
line-length = 100
target-version = ["py310", "py311", "py312"]
[tool.isort]
profile = "black"
line_length = 100
[tool.mypy]
python_version = "3.10"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = false
[tool.ruff]
line-length = 100
target-version = "py310"
[tool.ruff.lint]
select = [
"E", # pycodestyle
"W", # pycodestyle
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]
ignore = []
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = "-v --tb=short"
+30
View File
@@ -0,0 +1,30 @@
# Text2SQL Agent 依赖清单
# 使用 uv 或 pip 安装:pip install -r requirements.txt
# 核心框架
camel-ai>=0.2.0
# LLM API
openai>=1.0.0
# 向量数据库
chromadb>=0.4.0
sentencepiece>=0.1.99
accelerate>=0.20.0
safetensors>=0.4.0
# SQL 处理
sqlglot>=20.0.0
sqlparse>=0.4.0
# 配置与验证
pydantic>=2.0.0
pydantic-settings>=2.0.0
python-dotenv>=1.0.0
# 工具库
tenacity>=8.0.0
structlog>=23.0.0
tqdm>=4.65.0
jieba>=0.42.0
numpy>=1.24.0,<2
+1
View File
@@ -0,0 +1 @@
# schema 包初始化
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+229
View File
@@ -0,0 +1,229 @@
"""
Schema向量索引构建器 - 基于ChromaDB
"""
import chromadb
from chromadb.config import Settings as ChromaSettings
from typing import Any, List, Dict, Optional
import logging
from pathlib import Path
from schema.manager import SchemaManager
logger = logging.getLogger(__name__)
class SchemaIndexer:
"""
Schema向量索引器
功能:
1. 为表结构构建向量索引
2. 基于问题的表检索
3. 持久化存储和加载
"""
def __init__(
self,
embedder: Any,
persist_dir: str = "./data/embeddings",
collection_name: str = "schema_tables",
):
"""
初始化索引器
Args:
embedder: Embedding模型实例
persist_dir: 向量数据库持久化目录
collection_name: 集合名称
"""
self.embedder = embedder
self.persist_dir = Path(persist_dir)
self.persist_dir.mkdir(parents=True, exist_ok=True)
# 初始化ChromaDB客户端
self.client = chromadb.PersistentClient(
path=str(self.persist_dir),
settings=ChromaSettings(anonymized_telemetry=False),
)
# 获取或创建集合
self.collection = self.client.get_or_create_collection(
name=collection_name,
metadata={"hnsw:space": "cosine"}, # 使用余弦相似度
)
logger.info(f"[OK] 初始化SchemaIndexer: collection={collection_name}")
def build_index(
self,
schema_manager: SchemaManager,
batch_size: int = 32,
force_rebuild: bool = False,
) -> bool:
"""
为Schema构建向量索引
Args:
schema_manager: SchemaManager实例
batch_size: 批处理大小
force_rebuild: 是否强制重建(默认为False,增量更新)
Returns:
True=成功,False=已存在且未强制重建
"""
existing_ids = set(self.collection.get()["ids"]) if self.collection.count() > 0 else set()
if not force_rebuild and existing_ids:
logger.info(f"索引已存在({len(existing_ids)}条记录),跳过构建")
return False
if force_rebuild and existing_ids:
logger.info(f"强制重建索引,删除{len(existing_ids)}条旧记录")
self.collection.delete()
# 准备数据
table_texts = []
table_ids = []
table_metadatas = []
for table_info in schema_manager.get_table_for_embedding():
table_texts.append(table_info["text"])
table_ids.append(table_info["name"])
table_metadatas.append({
"table_name": table_info["name"],
"column_count": len(schema_manager.get_table(table_info["name"]).columns),
})
# 批量计算embedding
logger.info(f"计算{len(table_texts)}张表的embedding...")
embeddings = self.embedder.encode(table_texts, batch_size=batch_size)
# 存入ChromaDB
self.collection.add(
embeddings=embeddings.tolist(),
documents=table_texts,
metadatas=table_metadatas,
ids=table_ids,
)
logger.info(f"[OK] 索引构建完成,共{len(table_ids)}张表")
return True
def search(
self,
query: str,
top_k: int = 20,
score_threshold: float = 0.3,
) -> List[Dict]:
"""
检索相关表
Args:
query: 查询文本(用户问题)
top_k: 返回前K个结果
score_threshold: 相似度阈值(0-1),低于此值的结果会被过滤
Returns:
检索结果列表,按相似度降序排列
[
{
"table_name": "表名",
"score": 0.95,
"document": "表描述文本",
"metadata": {...}
},
...
]
"""
# 编码查询文本
query_embedding = self.embedder.encode([query])
# 执行检索
results = self.collection.query(
query_embeddings=query_embedding.tolist(),
n_results=min(top_k, self.collection.count()),
)
# 格式化结果
formatted = []
if results["ids"] and len(results["ids"][0]) > 0:
for idx, (table_id, distance, metadata, document) in enumerate(zip(
results["ids"][0],
results["distances"][0],
results["metadatas"][0],
results["documents"][0],
)):
score = 1 - distance # 余弦相似度(已归一化,转换为0-1,越大越相似)
if score >= score_threshold:
formatted.append({
"table_name": table_id,
"score": float(score),
"document": document,
"metadata": metadata,
"rank": idx + 1,
})
logger.debug(f"检索 '{query[:50]}...' -> 找到{len(formatted)}个相关表(阈值={score_threshold})")
return formatted
def search_by_table_names(self, table_names: List[str]) -> List[Dict]:
"""
直接通过表名获取表信息
Args:
table_names: 表名列表
Returns:
表信息列表
"""
results = []
for name in table_names:
try:
result = self.collection.get(ids=[name], include=["metadatas", "documents"])
if result["ids"]:
results.append({
"table_name": name,
"score": 1.0,
"document": result["documents"][0],
"metadata": result["metadatas"][0],
})
except Exception as e:
logger.warning(f"获取表信息失败 {name}: {e}")
return results
def get_all_tables(self) -> List[str]:
"""获取索引中的所有表名"""
result = self.collection.get()
return result["ids"] if result["ids"] else []
def delete_table(self, table_name: str):
"""从索引中删除表"""
self.collection.delete(ids=[table_name])
logger.info(f"已删除表索引: {table_name}")
def clear(self):
"""清空索引"""
self.collection.delete()
logger.info("索引已清空")
def count(self) -> int:
"""获取索引中的表数量"""
return self.collection.count()
# ========== 统计与调试 ==========
def get_statistics(self) -> Dict:
"""获取索引统计信息"""
count = self.collection.count()
result = self.collection.get(include=["metadatas"])
total_columns = sum(m.get("column_count", 0) for m in result["metadatas"])
return {
"indexed_tables": count,
"total_columns": total_columns,
"avg_columns": total_columns / count if count > 0 else 0,
"persist_dir": str(self.persist_dir),
}
+319
View File
@@ -0,0 +1,319 @@
"""
Schema加载器 - 解析JSON/DDL格式的数据库Schema
"""
import json
import re
from pathlib import Path
from typing import List, Dict, Optional, Tuple
import logging
from .models import Table, Column, ForeignKey, DatabaseSchema
logger = logging.getLogger(__name__)
class SchemaLoader:
"""Schema加载器 - 支持JSON和DDL格式"""
def __init__(self, schema_dir: str = None):
"""
初始化Schema加载器
Args:
schema_dir: Schema文件目录路径
"""
self.schema_dir = Path(schema_dir) if schema_dir else None
def load_from_json(
self, json_path: str, g3sb_meta_path: Optional[str] = None
) -> DatabaseSchema:
"""
从JSON文件加载Schema
JSON格式示例:
{
"database": "db_name",
"tables": [
{
"name": "table1",
"comment": "表描述",
"columns": [
{"name": "col1", "type": "INT", "comment": "...", "nullable": false}
],
"primary_keys": ["col1"],
"foreign_keys": [
{"columns": ["col2"], "ref_table": "table2", "ref_columns": ["col1"]}
]
}
]
}
亦支持 G3SB table_structure.json:顶层为 ``schemas`` 字典(与 ``tables`` 数组二选一
时优先使用非空的 ``schemas``)。可选 ``g3sb_meta_path`` 指向 table_meta.json
以合并表级注释。
Args:
json_path: JSON文件路径
g3sb_meta_path: 可选,G3SB table_meta.json(含 tables.{表名}.comment)
Returns:
DatabaseSchema对象
"""
path = Path(json_path)
if not path.exists():
raise FileNotFoundError(f"Schema文件不存在: {json_path}")
with open(path, 'r', encoding='utf-8') as f:
data = json.load(f)
# 提取数据库名
db_name = data.get("database", path.stem)
schemas_map = data.get("schemas")
tables_data = data.get("tables")
# 优先非空 schemas(G3SB 结构字典),避免误把其它 truthy 的 tables 键当好列表解析
if isinstance(schemas_map, dict) and schemas_map:
table_meta: Dict = {}
if g3sb_meta_path:
mp = Path(g3sb_meta_path)
if mp.is_file():
with open(mp, 'r', encoding='utf-8') as mf:
meta_data = json.load(mf)
table_meta = meta_data.get("tables", {}) or {}
else:
logger.warning(
"G3SB meta 文件不存在,将跳过表注释: %s", g3sb_meta_path
)
tables = []
for table_name, structure_str in schemas_map.items():
if not isinstance(structure_str, str):
continue
comment = None
if table_meta and isinstance(table_meta.get(table_name), dict):
comment = table_meta[table_name].get("comment")
columns = self._parse_g3sb_table_structure(structure_str)
tables.append(
Table(
name=table_name,
comment=comment,
columns=columns,
primary_keys=self._extract_primary_keys(columns),
foreign_keys=[],
)
)
logger.info(
"[OK] 加载Schema完成(G3SB schemas): %s, 共%d张表", db_name, len(tables)
)
return DatabaseSchema(name=db_name, tables=tables)
if isinstance(tables_data, list) and tables_data:
tables = [self._parse_table(table_data) for table_data in tables_data]
logger.info(f"[OK] 加载Schema完成: {db_name}, 共{len(tables)}张表")
return DatabaseSchema(name=db_name, tables=tables)
tables = []
logger.info(f"[OK] 加载Schema完成: {db_name}, 共{len(tables)}张表")
return DatabaseSchema(name=db_name, tables=tables)
def load_from_g3sb_format(self, meta_path: str, structure_path: str) -> DatabaseSchema:
"""
加载G3SB系统的数据字典格式(两个JSON文件)
Args:
meta_path: table_meta.json路径(表注释)
structure_path: table_structure.json路径(表结构)
Returns:
DatabaseSchema对象
"""
# 1. 加载表元数据(表注释)
with open(meta_path, 'r', encoding='utf-8') as f:
meta_data = json.load(f)
table_meta = meta_data.get("tables", {})
# 2. 加载表结构
with open(structure_path, 'r', encoding='utf-8') as f:
structure_data = json.load(f)
table_structures = structure_data.get("schemas", {})
# 3. 解析所有表
tables = []
for table_name, structure_str in table_structures.items():
comment = table_meta.get(table_name, {}).get("comment")
# 解析表结构字符串
# 格式: "TABLE TableName (col1:TYPE -- comment, col2:TYPE, ...)"
columns = self._parse_g3sb_table_structure(structure_str)
table = Table(
name=table_name,
comment=comment,
columns=columns,
primary_keys=self._extract_primary_keys(columns),
foreign_keys=[] # G3SB格式没有外键信息,后续可补充
)
tables.append(table)
logger.info(f"[OK] 加载G3SB Schema完成: 共{len(tables)}张表")
return DatabaseSchema(name="G3SB_DB", tables=tables)
def _parse_table(self, data: Dict) -> Table:
"""解析单表JSON数据"""
columns = []
for col_data in data.get("columns", []):
col = Column(
name=col_data["name"],
data_type=col_data["type"],
comment=col_data.get("comment"),
nullable=col_data.get("nullable", True),
is_primary_key=col_data.get("is_primary_key", False),
)
columns.append(col)
# 外键解析
foreign_keys = []
for fk_data in data.get("foreign_keys", []):
fk = ForeignKey(
columns=fk_data["columns"],
ref_table=fk_data["ref_table"],
ref_columns=fk_data["ref_columns"],
)
foreign_keys.append(fk)
return Table(
name=data["name"],
comment=data.get("comment"),
columns=columns,
primary_keys=data.get("primary_keys", []),
foreign_keys=foreign_keys,
)
def _parse_g3sb_table_structure(self, structure_str: str) -> List[Column]:
"""
解析G3SB格式的表结构字符串
示例:
"TABLE BCAccountCash (AccountID:NCHAR, RegionID:NCHAR, CurrencyID:NCHAR, Settled:DECIMAL -- Settled balance, ...)"
"""
# 提取括号内的内容
match = re.search(r'\((.*)\)', structure_str)
if not match:
logger.warning(f"无法解析表结构: {structure_str[:100]}")
return []
inner = match.group(1)
columns = []
# 按逗号分割字段(注意注释中可能包含逗号)
parts = self._split_columns(inner)
for part in parts:
part = part.strip()
if not part:
continue
# 解析字段定义:name:TYPE [-- comment]
# 支持格式: "FieldName:DATATYPE" 或 "FieldName:DATATYPE -- comment"
col_match = re.match(r'^(\w+)\s*:\s*([A-Za-z0-9()]+)', part)
if not col_match:
continue
col_name = col_match.group(1).strip()
col_type = col_match.group(2).strip()
# 提取注释(ASCII -- 或 G3SB 常用的 Unicode 长破折号 — U+2014)
comment = None
comment_match = re.search(r'(?:--|\u2014)\s*(.+)', part)
if comment_match:
comment = comment_match.group(1).strip()
# 判断是否可为空(通常有默认值或未标注NOT NULL即为NULL)
nullable = True # G3SB格式默认允许NULL
column = Column(
name=col_name,
data_type=col_type,
comment=comment,
nullable=nullable,
)
columns.append(column)
return columns
def _split_columns(self, inner: str) -> List[str]:
"""
按字段边界拆分(G3SB 注释里常有英文逗号,且用 — 而非 --)。
仅在「后面紧跟 标识符: 」的逗号处切分,这样注释内的逗号不会误拆列。
"""
if not inner or not inner.strip():
return []
# 下一列以 Name:TYPE 开头;避免在括号嵌套里误匹配可再收紧(当前 G3SB 类型无顶层逗号)
parts = re.split(r",\s*(?=\w+\s*:)", inner)
return [p.strip() for p in parts if p.strip()]
def _extract_primary_keys(self, columns: List[Column]) -> List[str]:
"""从字段列表中提取主键(简单启发式:字段名包含ID或明确标记)"""
pk_candidates = []
for col in columns:
# 简单规则:字段名以ID结尾,或名称包含key/id
if col.name.upper().endswith('ID') or 'KEY' in col.name.upper():
pk_candidates.append(col.name)
return pk_candidates[:1] # 暂时只取一个主键(简化)
def load_all_schemas(self) -> List[DatabaseSchema]:
"""
加载schema_dir下的所有Schema文件
Returns:
DatabaseSchema列表
"""
if not self.schema_dir:
raise ValueError("未指定schema_dir")
schemas = []
for json_file in self.schema_dir.glob("*.json"):
try:
schema = self.load_from_json(str(json_file))
schemas.append(schema)
except Exception as e:
logger.error(f"加载Schema失败 {json_file}: {e}")
logger.info(f"[OK] 共加载{len(schemas)}个Schema")
return schemas
# 便捷函数
def load_schema_from_g3sb(meta_path: str, structure_path: str) -> DatabaseSchema:
"""
从G3SB格式加载Schema的便捷函数
Args:
meta_path: table_meta.json路径
structure_path: table_structure.json路径
Returns:
DatabaseSchema对象
"""
loader = SchemaLoader()
return loader.load_from_g3sb_format(meta_path, structure_path)
def load_schema_from_json(
json_path: str, g3sb_meta_path: Optional[str] = None
) -> DatabaseSchema:
"""
从标准JSON加载Schema的便捷函数
Args:
json_path: JSON文件路径
g3sb_meta_path: 可选,G3SB table_meta.json
Returns:
DatabaseSchema对象
"""
loader = SchemaLoader()
return loader.load_from_json(json_path, g3sb_meta_path=g3sb_meta_path)
+315
View File
@@ -0,0 +1,315 @@
"""
Schema管理器 - 管理数据库Schema的加载、索引和检索
"""
import json
import hashlib
from pathlib import Path
from typing import List, Dict, Optional, Tuple
import logging
from .models import DatabaseSchema, Table
from .loader import SchemaLoader, load_schema_from_json, load_schema_from_g3sb
logger = logging.getLogger(__name__)
class SchemaManager:
"""
Schema管理器
功能:
1. 加载和解析Schema文件
2. 管理表关系
3. 提供表检索接口
4. 生成紧凑的Schema描述
"""
def __init__(self, schema: DatabaseSchema):
"""
初始化Schema管理器
Args:
schema: DatabaseSchema对象
"""
self.schema = schema
self._table_dict = {tbl.name: tbl for tbl in schema.tables}
self._embedding_index = None # 向量索引(延迟初始化)
self._cache = {}
@classmethod
def load_from_json(
cls, json_path: str, g3sb_meta_path: Optional[str] = None
) -> "SchemaManager":
"""
从JSON文件加载Schema
Args:
json_path: JSON文件路径
g3sb_meta_path: 可选,G3SB table_meta.json(与 table_structure 配对)
Returns:
SchemaManager实例
"""
schema = load_schema_from_json(json_path, g3sb_meta_path=g3sb_meta_path)
return cls(schema)
@classmethod
def load_from_g3sb(cls, meta_path: str, structure_path: str) -> "SchemaManager":
"""
从G3SB格式加载Schema
Args:
meta_path: table_meta.json路径
structure_path: table_structure.json路径
Returns:
SchemaManager实例
"""
schema = load_schema_from_g3sb(meta_path, structure_path)
return cls(schema)
@classmethod
def from_dict(cls, data: Dict) -> "SchemaManager":
"""
从字典创建SchemaManager
Args:
data: 包含database和tables的字典
Returns:
SchemaManager实例
"""
loader = SchemaLoader()
schema = loader._parse_table(data) if isinstance(data, dict) else None
if not schema:
raise ValueError("Invalid schema data")
return cls(schema)
# ========== 查询接口 ==========
def get_table(self, table_name: str) -> Optional[Table]:
"""获取指定表"""
return self._table_dict.get(table_name)
def list_tables(self) -> List[str]:
"""获取所有表名"""
return list(self._table_dict.keys())
def get_tables(self) -> List[Table]:
"""获取所有Table对象"""
return list(self._table_dict.values())
def get_related_tables(self, table_name: str, depth: int = 1) -> List[Table]:
"""
获取关联表(通过外键关系)
Args:
table_name: 起始表名
depth: 递归深度(1=直接关联,2=间接关联...)
Returns:
相关表列表
"""
result = set()
visited = set()
def _traverse(tname: str, current_depth: int):
if tname not in self._table_dict or current_depth > depth:
return
if tname in visited:
return
visited.add(tname)
table = self._table_dict[tname]
for fk in table.foreign_keys:
result.add(fk.ref_table)
_traverse(fk.ref_table, current_depth + 1)
# 反向外键(被引用的表)
for other_table in self._table_dict.values():
for fk in other_table.foreign_keys:
if fk.ref_table == tname:
result.add(other_table.name)
_traverse(other_table.name, current_depth + 1)
_traverse(table_name, 0)
return [self._table_dict[t] for t in result if t in self._table_dict]
# ========== Schema生成 ==========
def to_compact_string(
self,
table_names: List[str] = None,
include_columns: bool = True,
max_columns_per_table: int = 15,
) -> str:
"""
生成紧凑的Schema描述字符串(用于LLM输入)
Args:
table_names: 指定包含的表(None表示所有表)
include_columns: 是否包含字段详情
max_columns_per_table: 每表最多显示字段数
Returns:
Schema描述字符串
"""
if table_names is None:
tables = self.get_tables()
else:
missing = [n for n in table_names if n not in self._table_dict]
if missing:
logger.warning(
"以下表名不在已加载Schema中,已从本次Schema片段中省略: %s",
missing,
)
tables = [t for t in self.get_tables() if t.name in table_names]
lines = []
lines.append(f"数据库: {self.schema.name}")
lines.append(f"涉及表数: {len(tables)}")
lines.append("=" * 60)
lines.append("")
for table in tables:
lines.append(f"【表】{table.name}")
if table.comment:
lines.append(f" 描述: {table.comment}")
if include_columns and table.columns:
lines.append(f" 字段:")
for col in table.columns[:max_columns_per_table]:
pk_marker = " [PK]" if col.is_primary_key else ""
null_marker = " NOT NULL" if not col.nullable else ""
comment = f" -- {col.comment}" if col.comment else ""
lines.append(f" {col.name}: {col.data_type}{pk_marker}{null_marker}{comment}")
if len(table.columns) > max_columns_per_table:
lines.append(f" ... 还有 {len(table.columns) - max_columns_per_table} 个字段")
# 外键关系
if table.foreign_keys:
lines.append(" 外键:")
for fk in table.foreign_keys[:5]:
lines.append(
f" {', '.join(fk.columns)} → {fk.ref_table}({', '.join(fk.ref_columns)})"
)
lines.append("")
return "\n".join(lines)
def to_filtered_schema(self, table_names: List[str]) -> DatabaseSchema:
"""
根据表名过滤,生成子集Schema
Args:
table_names: 要保留的表名列表
Returns:
新的DatabaseSchema对象
"""
filtered_tables = [t for t in self.get_tables() if t.name in table_names]
return DatabaseSchema(
name=f"{self.schema.name}_filtered",
tables=filtered_tables,
)
# ========== 向量索引支持 ==========
def set_embeddings(self, table_embeddings: Dict[str, List[float]]):
"""
为表设置预计算的embedding向量
Args:
table_embeddings: {table_name: embedding_vector}
"""
for table in self.get_tables():
if table.name in table_embeddings:
table.embedding = table_embeddings[table.name]
def get_table_for_embedding(
self,
max_columns: int = 48,
max_col_comment_chars: int = 160,
max_total_chars: int = 8000,
) -> List[Dict]:
"""
获取用于embedding的表信息列表(单条文本同时承载 meta + structure 的可检索信息)。
- 表级:表名、表注释(来自 table_meta 合并后的 Table.comment)
- 列级:字段名、类型、主键标记、列注释(来自 table_structure 解析后的 Column)
Returns:
[{"name": "...", "text": "..."}, ...]
"""
result = []
for table in self.get_tables():
text_parts = [f"表名: {table.name}"]
if table.comment:
text_parts.append(f"描述: {table.comment}")
col_segments: List[str] = []
shown = table.columns[:max_columns]
for col in shown:
seg = f"{col.name} {col.data_type}"
if col.is_primary_key:
seg += " PK"
if col.comment:
c = col.comment.strip().replace("\n", " ")
if len(c) > max_col_comment_chars:
c = c[: max_col_comment_chars - 1] + "…"
seg += f" — {c}"
col_segments.append(seg)
if col_segments:
text_parts.append("字段: " + ";".join(col_segments))
if len(table.columns) > max_columns:
rest = len(table.columns) - max_columns
text_parts.append(f"另有{rest}个字段未列出(共{len(table.columns)}列)")
text = "。".join(text_parts)
if len(text) > max_total_chars:
text = text[: max_total_chars - 1] + "…"
result.append({
"name": table.name,
"text": text,
})
return result
# ========== 缓存支持 ==========
def get_cached_result(self, key: str) -> Optional[str]:
"""获取缓存结果"""
return self._cache.get(key)
def set_cached_result(self, key: str, value: str, ttl: int = 3600):
"""设置缓存结果"""
self._cache[key] = value
# TODO: 可扩展为Redis缓存
# ========== 统计信息 ==========
def get_statistics(self) -> Dict:
"""获取Schema统计信息"""
total_columns = sum(len(t.columns) for t in self.get_tables())
tables_with_pk = sum(1 for t in self.get_tables() if t.primary_keys)
tables_with_fk = sum(1 for t in self.get_tables() if t.foreign_keys)
return {
"database": self.schema.name,
"total_tables": len(self.get_tables()),
"total_columns": total_columns,
"avg_columns_per_table": total_columns / len(self.get_tables()) if self.get_tables() else 0,
"tables_with_primary_key": tables_with_pk,
"tables_with_foreign_key": tables_with_fk,
"table_names": self.list_tables(),
}
def __len__(self) -> int:
return len(self.get_tables())
def __repr__(self) -> str:
return f"SchemaManager(database={self.schema.name}, tables={len(self)})"
+179
View File
@@ -0,0 +1,179 @@
"""
Schema数据模型定义
"""
from dataclasses import dataclass, field
from typing import List, Optional, Dict, Any
from datetime import datetime
@dataclass
class Column:
"""列字段定义"""
name: str
data_type: str
comment: Optional[str] = None
nullable: bool = True
is_primary_key: bool = False
is_foreign_key: bool = False
def __str__(self):
null_str = "NULL" if self.nullable else "NOT NULL"
pk_str = " PK" if self.is_primary_key else ""
comment_str = f" -- {self.comment}" if self.comment else ""
return f"{self.name} {self.data_type}{null_str}{pk_str}{comment_str}"
@dataclass
class ForeignKey:
"""外键关系"""
columns: List[str] # 本表字段
ref_table: str # 引用表
ref_columns: List[str] # 引用字段
@dataclass
class Table:
"""数据表定义"""
name: str
comment: Optional[str] = None
columns: List[Column] = field(default_factory=list)
primary_keys: List[str] = field(default_factory=list)
foreign_keys: List[ForeignKey] = field(default_factory=list)
# 向量embedding(可选,用于检索)
embedding: Optional[Any] = None
@property
def column_dict(self) -> Dict[str, Column]:
"""字段名到Column对象的映射"""
return {col.name: col for col in self.columns}
@property
def column_names(self) -> List[str]:
"""所有字段名列表"""
return [col.name for col in self.columns]
def to_compact_string(self, max_columns: int = 20) -> str:
"""
生成紧凑的Schema字符串(用于LLM输入)
Args:
max_columns: 最大字段数,超过时截断
Returns:
紧凑的Schema描述字符串
"""
parts = [f"TABLE {self.name} ("]
# 只显示关键字段(主键、常见字段)
display_columns = self.columns[:max_columns] if len(self.columns) > max_columns else self.columns
col_strs = []
for col in display_columns:
col_str = f" {col.name}: {col.data_type}"
if col.is_primary_key:
col_str += " [PK]"
if col.comment:
col_str += f" -- {col.comment}"
col_strs.append(col_str)
parts.append(",\n".join(col_strs))
if len(self.columns) > max_columns:
parts.append(f"\n -- 还有 {len(self.columns) - max_columns} 个字段未显示")
parts.append(")")
return "".join(parts)
def to_dict(self) -> Dict:
"""转换为字典格式"""
return {
"name": self.name,
"comment": self.comment,
"columns": [
{
"name": col.name,
"data_type": col.data_type,
"comment": col.comment,
"nullable": col.nullable,
"is_primary_key": col.is_primary_key,
}
for col in self.columns
],
"primary_keys": self.primary_keys,
"foreign_keys": [
{
"columns": fk.columns,
"ref_table": fk.ref_table,
"ref_columns": fk.ref_columns,
}
for fk in self.foreign_keys
],
}
@dataclass
class DatabaseSchema:
"""数据库Schema(多个表的集合)"""
name: str
tables: List[Table] = field(default_factory=list)
created_at: datetime = field(default_factory=datetime.now)
@property
def table_dict(self) -> Dict[str, Table]:
"""表名字典"""
return {tbl.name: tbl for tbl in self.tables}
def get_table(self, table_name: str) -> Optional[Table]:
"""获取指定表"""
return self.table_dict.get(table_name)
def to_summary_string(self, include_columns: bool = True) -> str:
"""
生成Schema摘要字符串(用于LLM输入)
Args:
include_columns: 是否包含字段信息
Returns:
Schema描述字符串
"""
lines = [f"数据库: {self.name}\n"]
lines.append(f"表总数: {len(self.tables)}\n")
lines.append("=" * 60 + "\n")
for table in self.tables:
lines.append(f"表名: {table.name}")
if table.comment:
lines.append(f"描述: {table.comment}")
lines.append(f"字段数: {len(table.columns)}")
if include_columns and table.columns:
lines.append("字段列表:")
for col in table.columns[:30]: # 限制字段数
pk_marker = " [PK]" if col.is_primary_key else ""
null_marker = " NULL" if col.nullable else " NOT NULL"
comment = f" -- {col.comment}" if col.comment else ""
lines.append(f" {col.name}: {col.data_type}{pk_marker}{null_marker}{comment}")
if len(table.columns) > 30:
lines.append(f" ... 还有 {len(table.columns) - 30} 个字段")
# 外键关系
if table.foreign_keys:
lines.append("外键关系:")
for fk in table.foreign_keys[:5]:
lines.append(
f" {', '.join(fk.columns)} -> {fk.ref_table}({', '.join(fk.ref_columns)})"
)
lines.append("") # 空行分隔
return "\n".join(lines)
def to_compact_dict(self) -> Dict:
"""紧凑字典格式(用于序列化)"""
return {
"database": self.name,
"tables": [tbl.to_dict() for tbl in self.tables],
}
+249
View File
@@ -0,0 +1,249 @@
"""
Text2SQL Few-shot 集成示例
展示如何在现有系统中集成经验数据集few-shot功能
"""
from typing import Optional, List
def enhance_orchestrator_with_fewshot(orchestrator_class):
"""
装饰器:为Text2SQLOrchestrator添加few-shot功能
用法:
from agents.orchestrator import Text2SQLOrchestrator
EnhancedOrchestrator = enhance_orchestrator_with_fewshot(Text2SQLOrchestrator)
orch = EnhancedOrchestrator(..., fewshot_enabled=True, fewshot_top_k=3)
"""
class FewShotEnhancedOrchestrator(orchestrator_class):
"""增强版Orchestrator,支持few-shot"""
def __init__(
self,
*args,
fewshot_enabled: bool = True,
fewshot_samples_path: Optional[str] = None,
fewshot_top_k: int = 3,
fewshot_min_rating: int = 7,
**kwargs
):
super().__init__(*args, **kwargs)
self.fewshot_enabled = fewshot_enabled
self.fewshot_top_k = fewshot_top_k
self.fewshot_min_rating = fewshot_min_rating
self.fewshot_selector = None
if fewshot_enabled:
from utils.fewshot_selector import FewShotSelector
path = fewshot_samples_path or "data/experiences/all_samples.jsonl"
self.fewshot_selector = FewShotSelector(path)
print(f"✅ Few-shot已启用: top_k={fewshot_top_k}, min_rating={fewshot_min_rating}")
def _generate_sql_with_fewshot(
self,
question: str,
schema_str: str,
dialect: str = "tsql"
) -> str:
"""带few-shot的SQL生成"""
from llm.deepseek_client import DeepSeekConfig
# 获取few-shot示例
examples_prompt = ""
if self.fewshot_selector:
examples = self.fewshot_selector.select(
question=question,
top_k=self.fewshot_top_k,
min_rating=self.fewshot_min_rating,
exclude_qids=[] # 可排除当前问题(如果已存在)
)
if examples:
examples_prompt = "\n\n".join([
f"示例 {i+1}:\n问题:{ex.question_zh}\nSQL:\n{ex.sql}"
for i, ex in enumerate(examples)
])
examples_prompt = f"参考以下相似示例:\n\n{examples_prompt}\n\n"
# 构造增强的Prompt
from config.prompts import SQL_GENERATOR_SYSTEM, SQL_GENERATOR_USER
user_content = f"""{examples_prompt}
当前问题:{question}
Schema信息:
{schema_str}
数据库方言:{dialect}
请参考上述示例的SQL编写风格,生成**有用 SQL**:
- 与示例保持相同的版式(大写关键字、4空格缩进、PascalCase别名)
- 根据当前Schema选择正确的表和字段
- 输出纯SQL,不要其他内容"""
messages = [
{"role": "system", "content": SQL_GENERATOR_SYSTEM},
{"role": "user", "content": user_content}
]
# 调用LLM
config = DeepSeekConfig(
api_key=self.deepseek.config.api_key,
base_url=self.deepseek.config.base_url,
model_name=self.deepseek.config.model_name,
temperature=0.3,
max_tokens=4096
)
from llm.deepseek_client import DeepSeekClient
client = DeepSeekClient(config)
response = client.chat(messages)
sql = response.content.strip()
# 清理代码块
if "```sql" in sql:
sql = sql[sql.find("```sql")+6:sql.find("```", sql.find("```sql")+6)].strip()
elif "```" in sql:
sql = sql[sql.find("```")+3:sql.find("```", sql.find("```")+3)].strip()
from utils.sql_parser import normalize_sql_for_dialect
return normalize_sql_for_dialect(sql, dialect)
# 重写 _generate_sql 方法
def _generate_sql(
self,
question: str,
schema_str: str,
dialect: str = "tsql"
) -> str:
if self.fewshot_enabled and self.fewshot_selector:
return self._generate_sql_with_fewshot(question, schema_str, dialect)
else:
return super()._generate_sql(question, schema_str, dialect)
return FewShotEnhancedOrchestrator
# ========== 集成步骤 ==========
def integrate_fewshot():
"""
集成few-shot功能的完整步骤
"""
print("=" * 60)
print("Few-shot 集成指南")
print("=" * 60)
steps = """
**步骤1:确保经验数据集已生成**
```bash
cd text2sql_agent_camel
python scripts/parse_examples.py
```
生成: data/experiences/all_samples.jsonl
**步骤2:修改 agents/orchestrator.py**
在文件开头添加:
```python
from utils.fewshot_selector import FewShotSelector
```
修改 Text2SQLOrchestrator.__init__:
```python
def __init__(self, ..., fewshot_enabled=True, fewshot_top_k=3, ...):
# ... 原有代码 ...
self.fewshot_enabled = fewshot_enabled
self.fewshot_top_k = fewshot_top_k
self.fewshot_selector = None
if fewshot_enabled:
self.fewshot_selector = FewShotSelector(
os.getenv("FEWSHOT_DATA_PATH", "data/experiences/all_samples.jsonl")
)
logger.info(f"Few-shot已启用: top_k={fewshot_top_k}")
```
修改 _generate_sql 方法(约第251行):
```python
def _generate_sql(self, question: str, schema_str: str, dialect: str = "tsql") -> str:
# 添加few-shot增强
if self.fewshot_enabled and self.fewshot_selector:
examples = self.fewshot_selector.select(
question=question,
top_k=self.fewshot_top_k,
min_rating=7,
exclude_qids=[] # 可选:排除当前问题对应的QID
)
if examples:
examples_prompt = "\\n\\n".join([
f"示例({ex.qid}):\\n问题:{ex.question_zh}\\nSQL:\\n{ex.sql}"
for ex in examples
])
# 将examples_prompt注入到用户消息中
# (需要调整 deepseek_client 调用逻辑)
# ... 原有生成逻辑 ...
```
**步骤3:配置环境变量(可选)**
```bash
# .env 文件添加
FEWSHOT_ENABLED=true
FEWSHOT_TOP_K=3
FEWSHOT_MIN_RATING=7
FEWSHOT_DATA_PATH=./data/experiences/all_samples.jsonl
```
**步骤4:测试效果**
```bash
# 对比测试
python main.py "查询2024年1月的销售额" --verbose
# 观察日志中的 "Few-shot已选择: Q31, Q6, Q44"
```
**步骤5:A/B测试评估**
```python
# 创建对比脚本
from agents.orchestrator import Text2SQLOrchestrator
# 无few-shot
orch_baseline = Text2SQLOrchestrator(..., fewshot_enabled=False)
result1 = orch_baseline.generate(question)
# 有few-shot
orch_fewshot = Text2SQLOrchestrator(..., fewshot_enabled=True, fewshot_top_k=3)
result2 = orch_fewshot.generate(question)
print(f"Baseline: {result1.sql[:100]}")
print(f"Few-shot: {result2.sql[:100]}")
```
"""
print(steps)
def quick_test_fewshot():
"""快速测试few-shot选择器"""
from utils.fewshot_selector import FewShotSelector
selector = FewShotSelector("data/experiences/all_samples.jsonl")
test_questions = [
"查询2024年1月的销售额",
"统计所有活跃账户数量",
"按对手方列出未结算交易",
"查询今天的现金余额",
]
print("\nFew-shot选择测试:\n")
for q in test_questions:
print(f"问题: {q}")
examples = selector.select(q, top_k=2, min_rating=8)
for ex in examples:
print(f" [{ex.qid}] {ex.question_zh[:40]}... (rating={ex.rating})")
print()
if __name__ == "__main__":
integrate_fewshot()
# quick_test_fewshot()
+439
View File
@@ -0,0 +1,439 @@
#!/usr/bin/env python3
"""
将 Example_text2sql.md 解析为结构化数据集
输出格式:
1. JSONL格式(每行一个样本)
2. 按难度/类别分类
3. 包含Schema、SQL、执行结果、评分
"""
import re
import json
import yaml
from pathlib import Path
from typing import List, Dict, Optional, Any
from dataclasses import dataclass, asdict
from datetime import datetime
@dataclass
class Text2SQLSample:
"""单条Text2SQL样本"""
qid: str # 问题ID,如 "Q1"
question_zh: str # 中文问题
sql: str # SQL语句
schema_info: Dict[str, Any] # Schema信息(表、字段)
explanation: str = "" # SQL理由
question_en: Optional[str] = None # 英文问题(如有)
rating: Optional[int] = None # 准确度评分 1-10
execution_result: Optional[List[Dict]] = None # 执行结果(表格)
result_note: str = "" # 结果说明(如"当前查询无结果")
tags: List[str] = None # 标签(如["聚合", "JOIN", "日期筛选"])
difficulty: str = "medium" # 难度:easy/medium/hard
def __post_init__(self):
if self.tags is None:
self.tags = []
def to_dict(self):
return asdict(self)
def to_fewshot_example(self) -> str:
"""转换为few-shot示例字符串"""
return f"""问题:{self.question_zh}
Schema:{json.dumps(self.schema_info, ensure_ascii=False)[:500]}
SQL:
{self.sql}
"""
class ExampleText2SQLParser:
"""解析 Example_text2sql.md 文件"""
def __init__(self, md_path: str):
self.md_path = Path(md_path)
self.content = self.md_path.read_text(encoding='utf-8')
self.samples: List[Text2SQLSample] = []
def parse(self) -> List[Text2SQLSample]:
"""解析整个MD文件"""
# 按问题分割(## Qxx. 标题)
q_blocks = re.split(r'\n## Q(\d+)\. ', self.content)
# q_blocks[0] 是文件头(目录、固定日期说明等),跳过
for i in range(1, len(q_blocks)):
qid_num = q_blocks[i].split('\n')[0].strip() # 从分割中获取问题号
# 实际qid应为 "Q{num}"
# 重新用正则匹配完整的Q标题
pass
# 更稳健的方法:直接用正则查找所有Q标题块
pattern = r'(## Q(\d+)\. .*?)(?=\n## Q\d+\. |\Z)'
matches = re.findall(pattern, self.content, re.DOTALL)
print(f"找到 {len(matches)} 个问答对")
for full_match, qid in matches:
sample = self._parse_single_block(qid, full_match)
if sample:
self.samples.append(sample)
return self.samples
def _parse_single_block(self, qid: str, block: str) -> Optional[Text2SQLSample]:
"""解析单个问答块"""
try:
lines = block.strip().split('\n')
# 提取问题(支持中英文双语)
# 格式:### 问题 后跟英文段落,空行,然后中文段落
question_zh = ""
question_en = ""
found_question_header = False
paragraph_lines = []
paragraphs = []
for line in lines:
if line.startswith('### 问题'):
found_question_header = True
continue
if not found_question_header:
continue
if line.startswith('###'):
# 遇到下一节,停止
break
if line.strip() == '':
# 空行:段落结束
if paragraph_lines:
paragraphs.append(' '.join(paragraph_lines).strip())
paragraph_lines = []
else:
paragraph_lines.append(line.strip())
# 最后一个段落
if paragraph_lines:
paragraphs.append(' '.join(paragraph_lines).strip())
# 第一段为英文,第二段为中文
if len(paragraphs) >= 1:
question_en = paragraphs[0]
if len(paragraphs) >= 2:
question_zh = paragraphs[1]
# 提取SQL
sql_match = re.search(r'```sql\n(.*?)\n```', block, re.DOTALL)
if not sql_match:
return None
sql = sql_match.group(1).strip()
# 提取SQL理由(### SQL理由 后面的内容)
reason_match = re.search(r'### SQL理由\n\n(.*?)(?=\n### |\Z)', block, re.DOTALL)
explanation = reason_match.group(1).strip() if reason_match else ""
# 提取评分(### SQL准确度评分)
rating_match = re.search(r'\*\*评分:\s*(\d+)/10\*\*', block)
rating = int(rating_match.group(1)) if rating_match else None
# 提取结果说明(### SQL执行结果 后面)
result_match = re.search(r'### SQL执行结果\n\n(.*?)(?=\n### |\Z)', block, re.DOTALL)
result_note = result_match.group(1).strip() if result_match else ""
# 推断标签
tags = self._infer_tags(question_zh, sql)
# 推断难度
difficulty = self._infer_difficulty(sql, tags)
# 构建Schema信息(从SQL中提取的表和字段)
schema_info = self._extract_schema_from_sql(sql)
return Text2SQLSample(
qid=f"Q{qid}",
question_zh=question_zh.strip(),
question_en=question_en.strip() if question_en else None,
sql=sql,
schema_info=schema_info,
explanation=explanation,
rating=rating,
result_note=result_note,
tags=tags,
difficulty=difficulty
)
except Exception as e:
print(f"解析 {qid} 失败: {e}")
return None
def _infer_tags(self, question: str, sql: str) -> List[str]:
"""推断问题标签"""
tags = []
q_lower = question.lower()
sql_upper = sql.upper()
# 按业务域
if any(k in q_lower for k in ['对手方', 'broker', '经纪商']):
tags.append('broker')
if any(k in q_lower for k in ['账户', 'account', '客户']):
tags.append('account')
if any(k in q_lower for k in ['现金', 'cash', '余额']):
tags.append('cash')
if any(k in q_lower for k in ['持仓', 'holding', 'position']):
tags.append('holding')
if any(k in q_lower for k in ['交易', 'trade', 'commission']):
tags.append('trade')
if any(k in q_lower for k in ['IPO', '认购', 'subscription']):
tags.append('ipo')
if any(k in q_lower for k in ['公司行动', 'corporate action', '权益']):
tags.append('corporate_action')
if any(k in q_lower for k in ['汇率', 'exchange rate']):
tags.append('exchange_rate')
if any(k in q_lower for k in ['保证金', 'margin']):
tags.append('margin')
if any(k in q_lower for k in ['利息', 'interest']):
tags.append('interest')
if any(k in q_lower for k in ['报表', 'statement']):
tags.append('statement')
# 按SQL特征
if 'GROUP BY' in sql_upper:
tags.append('aggregation')
if 'JOIN' in sql_upper:
tags.append('join')
if 'WHERE' in sql_upper:
tags.append('filter')
if re.search(r'DATE.*BETWEEN|>=.*AND', sql_upper) or 'BETWEEN' in sql_upper:
tags.append('date_range')
if re.search(r'\bCOUNT\b|\bSUM\b|\bAVG\b|\bMAX\b|\bMIN\b', sql_upper):
tags.append('aggregation')
if 'ORDER BY' in sql_upper:
tags.append('ordering')
if 'TOP' in sql_upper or 'LIMIT' in sql_upper:
tags.append('limit')
if 'LEFT JOIN' in sql_upper:
tags.append('left_join')
if 'UNION' in sql_upper:
tags.append('union')
if re.search(r'DATEADD|DATEDIFF|CAST.*GETDATE', sql_upper):
tags.append('date_function')
return list(set(tags))
def _infer_difficulty(self, sql: str, tags: List[str]) -> str:
"""推断难度"""
sql_upper = sql.upper()
# 简单规则
if 'UNION' in sql_upper or 'EXCEPT' in sql_upper or 'INTERSECT' in sql_upper:
return 'hard'
if sql.count('JOIN') >= 3:
return 'hard'
if 'GROUP BY' in sql_upper and 'HAVING' in sql_upper:
return 'hard'
if re.search(r'SUBQUERY|EXISTS.*SELECT', sql_upper, re.IGNORECASE):
return 'hard'
if len(tags) >= 5:
return 'hard'
if sql.count('JOIN') == 2 or 'GROUP BY' in sql_upper:
return 'medium'
return 'easy'
def _extract_schema_from_sql(self, sql: str) -> Dict[str, Any]:
"""从SQL中提取表结构信息"""
import sqlglot
from sqlglot import exp
schema = {
"tables": {},
"joins": []
}
try:
parsed = sqlglot.parse_one(sql, dialect='tsql')
# 提取所有表
for table in parsed.find_all(exp.Table):
table_name = table.name
alias = table.alias_or_name
schema["tables"][table_name] = {
"alias": alias,
"columns": []
}
# 提取所有列引用
for col in parsed.find_all(exp.Column):
table_name = col.table
col_name = col.name
if table_name in schema["tables"]:
if col_name not in schema["tables"][table_name]["columns"]:
schema["tables"][table_name]["columns"].append(col_name)
# 提取JOIN关系
for join in parsed.find_all(exp.Join):
schema["joins"].append({
"type": join.args.get('side', 'INNER'),
"on": str(join.args.get('on'))
})
except Exception as e:
print(f"SQL解析失败: {e}")
return schema
def save_jsonl(self, output_path: Path):
"""保存为JSONL格式"""
with output_path.open('w', encoding='utf-8') as f:
for sample in self.samples:
f.write(json.dumps(sample.to_dict(), ensure_ascii=False) + '\n')
print(f"[OK] 保存 {len(self.samples)} 条样本到 {output_path}")
def save_fewshot_prompt(self, output_path: Path, limit_per_tag: int = 2):
"""生成few-shot提示文件"""
examples_by_tag = {}
for sample in self.samples:
for tag in sample.tags:
if tag not in examples_by_tag:
examples_by_tag[tag] = []
if len(examples_by_tag[tag]) < limit_per_tag:
examples_by_tag[tag].append(sample)
with output_path.open('w', encoding='utf-8') as f:
f.write("# Few-shot Examples for Text2SQL\n\n")
f.write("以下是从经验数据集中精选的示例,用于辅助SQL生成。\n\n")
for tag, samples in sorted(examples_by_tag.items()):
f.write(f"## 标签: {tag}\n\n")
for i, sample in enumerate(samples, 1):
f.write(f"### 示例 {i}\n")
f.write(f"**问题**:{sample.question_zh}\n\n")
f.write(f"**SQL**:\n```sql\n{sample.sql}\n```\n\n")
f.write(f"**说明**:{sample.explanation[:200]}...\n\n")
f.write("\n")
print(f"[OK] Few-shot示例已保存到 {output_path}")
def save_by_category(self, output_dir: Path):
"""按标签分类保存"""
output_dir.mkdir(parents=True, exist_ok=True)
by_tag = {}
for sample in self.samples:
for tag in sample.tags:
if tag not in by_tag:
by_tag[tag] = []
by_tag[tag].append(sample)
for tag, samples in by_tag.items():
tag_file = output_dir / f"{tag}.jsonl"
with tag_file.open('w', encoding='utf-8') as f:
for sample in samples:
f.write(json.dumps(sample.to_dict(), ensure_ascii=False) + '\n')
print(f"[OK] 按标签分类保存到 {output_dir}({len(by_tag)}个类别)")
def generate_stats(self) -> Dict:
"""生成数据集统计"""
stats = {
"total_samples": len(self.samples),
"by_difficulty": {},
"by_tag": {},
"by_rating": {},
"avg_rating": 0,
}
# 难度分布
for diff in ['easy', 'medium', 'hard']:
stats["by_difficulty"][diff] = sum(
1 for s in self.samples if s.difficulty == diff
)
# 标签分布
tag_counts = {}
for sample in self.samples:
for tag in sample.tags:
tag_counts[tag] = tag_counts.get(tag, 0) + 1
stats["by_tag"] = tag_counts
# 评分分布
ratings = [s.rating for s in self.samples if s.rating is not None]
if ratings:
stats["avg_rating"] = sum(ratings) / len(ratings)
for r in range(1, 11):
stats["by_rating"][r] = ratings.count(r)
return stats
def main():
md_path = Path(__file__).parent.parent / "data" / "Example" / "Example_text2sql.md"
output_dir = Path(__file__).parent.parent / "data" / "experiences"
print("=" * 60)
print("Text2SQL 经验数据集构建工具")
print("=" * 60)
parser = ExampleText2SQLParser(md_path)
samples = parser.parse()
print(f"\n[OK] 解析完成,共 {len(samples)} 个样本")
# 生成统计
stats = parser.generate_stats()
print(f"\n[INFO] 数据集统计:")
print(f" 总样本数: {stats['total_samples']}")
print(f" 难度分布: {stats['by_difficulty']}")
print(f" 平均评分: {stats['avg_rating']:.1f}/10")
print(f"\n 标签分布(Top 10):")
sorted_tags = sorted(stats["by_tag"].items(), key=lambda x: -x[1])[:10]
for tag, count in sorted_tags:
print(f" {tag}: {count}")
# 保存输出
output_dir.mkdir(parents=True, exist_ok=True)
# 1. JSONL格式(所有样本)
parser.save_jsonl(output_dir / "all_samples.jsonl")
# 2. 按难度分类
for diff in ['easy', 'medium', 'hard']:
diff_samples = [s for s in samples if s.difficulty == diff]
if diff_samples:
with (output_dir / f"difficulty_{diff}.jsonl").open('w', encoding='utf-8') as f:
for s in diff_samples:
f.write(json.dumps(s.to_dict(), ensure_ascii=False) + '\n')
# 3. Few-shot提示文件
parser.save_fewshot_prompt(output_dir / "fewshot_examples.md")
# 4. 按标签分类
parser.save_by_category(output_dir / "by_tag")
# 5. 高评分样本(rating >= 8)
high_rating = [s for s in samples if s.rating and s.rating >= 8]
with (output_dir / "high_rating_samples.jsonl").open('w', encoding='utf-8') as f:
for s in high_rating:
f.write(json.dumps(s.to_dict(), ensure_ascii=False) + '\n')
print(f"\n[OK] 高评分样本(rating>=8): {len(high_rating)} 条")
# 6. 生成README
with (output_dir / "README.md").open('w', encoding='utf-8') as f:
f.write("# Text2SQL 经验数据集\n\n")
f.write(f"**来源**: `Example_text2sql.md`\n")
f.write(f"**样本数**: {len(samples)}\n")
f.write(f"**生成时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
f.write("## 文件说明\n\n")
f.write("- `all_samples.jsonl` - 所有样本(JSONL格式)\n")
f.write("- `difficulty_*.jsonl` - 按难度分类\n")
f.write("- `by_tag/` - 按标签分类(每个标签一个文件)\n")
f.write("- `fewshot_examples.md` - Few-shot示例(Markdown格式)\n")
f.write("- `high_rating_samples.jsonl` - 高评分样本(rating≥8)\n\n")
f.write("## 使用建议\n\n")
f.write("1. **Few-shot prompting**: 使用 `fewshot_examples.md` 中的示例\n")
f.write("2. **训练数据**: 使用 `all_samples.jsonl` 进行模型微调\n")
f.write("3. **评估测试**: 使用 `high_rating_samples.jsonl` 作为测试集\n")
f.write("4. **领域适应**: 按标签选择相关示例(如broker相关查询)\n")
print(f"\n[OK] 所有文件已保存到: {output_dir}")
if __name__ == "__main__":
main()
+237
View File
@@ -0,0 +1,237 @@
#!/usr/bin/env python3
"""
自动集成few-shot功能到 Text2SQL 系统
用法:
python scripts/patch_fewshot.py --enable --top-k 3 --min-rating 7
"""
import argparse
import re
from pathlib import Path
def patch_orchestrator(
enable: bool = True,
top_k: int = 3,
min_rating: int = 7,
data_path: str = "data/experiences/all_samples.jsonl"
):
"""
修改 agents/orchestrator.py 添加few-shot支持
"""
orch_path = Path(__file__).parent.parent / "agents" / "orchestrator.py"
if not orch_path.exists():
print(f"❌ 文件不存在: {orch_path}")
return False
content = orch_path.read_text(encoding='utf-8')
# 1. 在文件头部添加import
import_line = "from utils.fewshot_selector import FewShotSelector"
if import_line not in content:
# 找到合适的插入点(在其他import之后)
last_import = content.rfind("import ")
if last_import != -1:
insert_pos = content.find("\n", last_import) + 1
content = content[:insert_pos] + import_line + "\n" + content[insert_pos:]
print("✅ 添加 import: from utils.fewshot_selector import FewShotSelector")
# 2. 修改 __init__ 方法
init_pattern = r'def __init__\([\s\S]*?\):'
init_match = re.search(init_pattern, content)
if init_match:
init_text = content[init_match.start():init_match.end()]
# 检查是否已添加few-shot参数
if "fewshot_enabled" not in init_text:
# 在参数列表末尾添加(在max_retry之后)
new_params = """,
# Few-shot 配置
fewshot_enabled: bool = True,
fewshot_samples_path: Optional[str] = None,
fewshot_top_k: int = 3,
fewshot_min_rating: int = 7,"""
# 找到max_retry参数后插入
max_retry_pos = init_text.find("max_retry:")
if max_retry_pos != -1:
comma_pos = init_text.find(",", max_retry_pos) + 1
new_init = (
init_text[:comma_pos] +
new_params +
init_text[comma_pos:]
)
content = content[:init_match.start()] + new_init + content[init_match.end():]
print("✅ 修改 __init__: 添加few-shot参数")
# 在__init__方法体内添加few-shot初始化代码
# 找到"self.max_retry = max_retry"这一行
max_retry_assign = "self.max_retry = max_retry"
if max_retry_assign in content[init_match.start():init_match.end()]:
init_body_start = init_match.end()
init_body = content[init_body_start:init_body_start + 2000] # 读取前2000字符
if "self.fewshot_selector" not in init_body:
fewshot_init = '''
# Few-shot 初始化
self.fewshot_enabled = fewshot_enabled
self.fewshot_top_k = fewshot_top_k
self.fewshot_min_rating = fewshot_min_rating
self.fewshot_selector = None
if self.fewshot_enabled:
try:
from utils.fewshot_selector import FewShotSelector
path = fewshot_samples_path or os.getenv(
"FEWSHOT_DATA_PATH",
"./data/experiences/all_samples.jsonl"
)
self.fewshot_selector = FewShotSelector(path)
logger.info(
f"Few-shot已启用: top_k={fewshot_top_k}, "
f"min_rating={fewshot_min_rating}"
)
except Exception as e:
logger.warning(f"Few-shot加载失败: {e},将使用标准生成")
self.fewshot_enabled = False
'''
# 插入到self.max_retry赋值之后
insert_pos = content[init_match.start():].find(max_retry_assign)
if insert_pos != -1:
absolute_pos = init_match.start() + insert_pos + len(max_retry_assign) + 1
content = content[:absolute_pos] + fewshot_init + content[absolute_pos:]
print("✅ 修改 __init__: 添加few-shot初始化")
# 3. 修改 _generate_sql 方法
generate_pattern = r'def _generate_sql\([\s\S]*?\) -> str:'
generate_match = re.search(generate_pattern, content)
if generate_match:
generate_text = content[generate_match.start():generate_match.end()]
if "if self.fewshot_enabled" not in generate_text:
# 在方法开头注入few-shot逻辑
fewshot_logic = ''' # Few-shot 增强
if self.fewshot_enabled and self.fewshot_selector:
try:
examples = self.fewshot_selector.select(
question=question,
top_k=self.fewshot_top_k,
min_rating=self.fewshot_min_rating
)
if examples:
examples_prompt = "\\n".join([
f"示例 {i+1}:\\n问题:{ex.question_zh}\\nSQL:\\n{ex.sql}"
for i, ex in enumerate(examples)
])
examples_prompt = (
f"参考以下相似问题的SQL示例:\\n\\n{examples_prompt}\\n\\n"
f"请学习上述示例的SQL编写风格和模式,为当前问题生成SQL。"
)
# 注入到schema_str前或user_content中
# 这里选择在schema_str前添加
schema_str = f"{examples_prompt}Schema信息:\\n{schema_str}"
logger.debug(f"已注入 {len(examples)} 个few-shot示例")
except Exception as e:
logger.warning(f"Few-shot检索失败: {e}")
'''
# 插入到方法开头("dialect_label = dialect" 之前)
dialect_pos = content[generate_match.start():].find("dialect_label = dialect")
if dialect_pos != -1:
absolute_pos = generate_match.start() + dialect_pos
content = content[:absolute_pos] + fewshot_logic + content[absolute_pos:]
print("✅ 修改 _generate_sql: 注入few-shot逻辑")
# 保存修改
backup_path = orch_path.with_suffix('.py.bak')
orch_path.write_text(content, encoding='utf-8')
print(f"✅ 已修改 {orch_path}")
print(f" 备份文件: {backup_path}")
return True
def create_env_config(top_k: int, min_rating: int):
"""更新.env文件添加few-shot配置"""
env_path = Path(__file__).parent.parent / ".env"
if not env_path.exists():
print(f"⚠️ .env文件不存在: {env_path}")
return
content = env_path.read_text(encoding='utf-8')
additions = f"""
# Few-shot 配置
FEWSHOT_ENABLED=true
FEWSHOT_TOP_K={top_k}
FEWSHOT_MIN_RATING={min_rating}
FEWSHOT_DATA_PATH=./data/experiences/all_samples.jsonl
"""
# 检查是否已存在
if "FEWSHOT_ENABLED" not in content:
with env_path.open('a', encoding='utf-8') as f:
f.write(additions)
print(f"✅ 已添加Few-shot配置到 .env")
else:
print(f"ℹ️ .env 中已存在FEWSHOT配置,跳过")
def main():
parser = argparse.ArgumentParser(description="集成Few-shot功能到Text2SQL系统")
parser.add_argument("--enable", action="store_true", help="启用few-shot")
parser.add_argument("--top-k", type=int, default=3, help="每次使用的示例数量")
parser.add_argument("--min-rating", type=int, default=7, help="示例最低评分")
parser.add_argument("--env-only", action="store_true", help="仅修改.env")
args = parser.parse_args()
if not args.enable and not args.env_only:
print("请使用 --enable 启用few-shot,或 --env-only 仅修改环境变量")
return
print("=" * 60)
print("Text2SQL Few-shot 集成工具")
print("=" * 60)
if args.env_only:
create_env_config(args.top_k, args.min_rating)
return
if args.enable:
print(f"\n配置: top_k={args.top_k}, min_rating={args.min_rating}")
# 1. 修改orchestrator.py
success = patch_orchestrator(
enable=True,
top_k=args.top_k,
min_rating=args.min_rating
)
if success:
# 2. 更新.env
create_env_config(args.top_k, args.min_rating)
print("\n" + "=" * 60)
print("✅ Few-shot集成完成!")
print("=" * 60)
print(f"\n下一步:")
print(f"1. 确保经验数据集已生成:")
print(f" python scripts/parse_examples.py")
print(f"\n2. 测试系统:")
print(f" python main.py \"查询2024年1月的销售额\" --verbose")
print(f"\n3. 查看日志中的few-shot选择:")
print(f" Few-shot已选择: Q31, Q6, Q44")
print(f"\n4. 调整参数:")
print(f" 编辑 .env 修改 FEWSHOT_TOP_K 和 FEWSHOT_MIN_RATING")
else:
print("❌ 集成失败")
if __name__ == "__main__":
main()
+1
View File
@@ -0,0 +1 @@
# utils 包初始化
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+530
View File
@@ -0,0 +1,530 @@
"""
Embedding 封装:本地 Qwen3-Embedding,或兼容 OpenAI /v1/embeddings 的远程 API
(ModelScope 推理、阿里云 DashScope 等)。
"""
import os
from typing import Union, List, Optional, Any
import numpy as np
from pathlib import Path
try:
from transformers import AutoModel, AutoTokenizer
import torch
_TRANSFORMERS_AVAILABLE = True
except ImportError:
_TRANSFORMERS_AVAILABLE = False
import logging
from dataclasses import dataclass
logger = logging.getLogger(__name__)
@dataclass
class _RemoteEmbeddingEnv:
"""从环境变量解析出的远程 OpenAI-Compatible Embedding 配置。"""
api_key: str
base_url: str
model: str
max_batch: int
label: str
def _remote_embedding_from_env() -> _RemoteEmbeddingEnv:
"""
优先 ModelScope(MODELSCOPE_*);未配置时回退 DashScope(DASHSCOPE_*)。
"""
ms_key = os.getenv("MODELSCOPE_API_KEY", "").strip()
ms_base = os.getenv("MODELSCOPE_BASE_URL", "").strip()
ds_key = os.getenv("DASHSCOPE_API_KEY", "").strip()
ds_base = (
os.getenv("DASHSCOPE_BASE_URL") or os.getenv("DASHSCOPE_base_url", "")
).strip()
# 仅当配置了 API Key 时走 ModelScope(避免仅有 BASE_URL 时误判、阻断 DashScope)
if ms_key:
base_url = ms_base or "https://api-inference.modelscope.cn/v1"
model = (
os.getenv("MODELSCOPE_EMBEDDING_MODEL")
or os.getenv("MODELSCOPE_MODEL", "Qwen/Qwen3-Embedding-8B")
).strip()
mb = os.getenv("MODELSCOPE_EMBEDDING_MAX_BATCH", "32").strip()
max_batch = max(1, int(mb)) if mb.isdigit() else 32
if not model:
raise ValueError("未配置 MODELSCOPE_EMBEDDING_MODEL(或 MODELSCOPE_MODEL)")
return _RemoteEmbeddingEnv(
api_key=ms_key,
base_url=base_url.rstrip("/"),
model=model,
max_batch=max_batch,
label="ModelScope",
)
# OpenAI 官方或兼容网关:OPENAI_API_KEY、OPENAI_EMBEDDING_MODEL、可选 OPENAI_BASE_URL
oa_key = os.getenv("OPENAI_API_KEY", "").strip()
if oa_key:
if oa_key.startswith("http://") or oa_key.startswith("https://"):
raise ValueError(
"OPENAI_API_KEY 不能填写为 URL:请将网关地址写到 OPENAI_BASE_URL"
"(例如 http://host:9080/v1),密钥单独写在 OPENAI_API_KEY"
)
oa_base = (
os.getenv("OPENAI_BASE_URL", "").strip() or "https://api.openai.com/v1"
)
oa_model = os.getenv("OPENAI_EMBEDDING_MODEL", "").strip()
if not oa_model:
raise ValueError(
"使用 OpenAI 兼容 Embedding 时请设置 OPENAI_EMBEDDING_MODEL"
)
mb = os.getenv("OPENAI_EMBEDDING_MAX_BATCH", "100").strip()
max_batch = max(1, int(mb)) if mb.isdigit() else 100
return _RemoteEmbeddingEnv(
api_key=oa_key,
base_url=oa_base.rstrip("/"),
model=oa_model,
max_batch=max_batch,
label="OpenAI",
)
if not ds_key:
raise ValueError(
"远程 Embedding 未配置:请设置 MODELSCOPE_API_KEY(及可选 BASE_URL),"
"或 OPENAI_API_KEY / OPENAI_EMBEDDING_MODEL(及可选 OPENAI_BASE_URL),"
"或 DASHSCOPE_API_KEY / DASHSCOPE_BASE_URL / DASHSCOPE_MODEL"
)
if not ds_base:
raise ValueError("未配置 DASHSCOPE_BASE_URL(或 DASHSCOPE_base_url)")
model = os.getenv("DASHSCOPE_MODEL", "").strip()
if not model:
raise ValueError("未配置 DASHSCOPE_MODEL")
mb = os.getenv("DASHSCOPE_EMBEDDING_MAX_BATCH", "10").strip()
max_batch = max(1, int(mb)) if mb.isdigit() else 10
return _RemoteEmbeddingEnv(
api_key=ds_key,
base_url=ds_base.rstrip("/"),
model=model,
max_batch=max_batch,
label="DashScope",
)
class Qwen3Embedding:
"""
Qwen3-Embedding-0.6B 向量化封装
使用 Mean Pooling 将token embeddings聚合为句子向量,
并进行L2归一化以支持余弦相似度计算。
"""
def __init__(
self,
model_path: Optional[str] = None,
device: Optional[str] = None,
use_fp16: bool = False
):
"""
初始化 embedding 模型
Args:
model_path: 本地模型路径,若为None则从环境变量或默认路径加载
device: 推理设备('cpu', 'cuda', 'cuda:0'等),None则自动选择
use_fp16: 是否使用FP16混合精度(GPU可用时建议开启,速度更快)
"""
if not _TRANSFORMERS_AVAILABLE:
raise ImportError(
"transformers 和 torch 未安装。请运行:\n"
"pip install transformers torch sentencepiece accelerate"
)
# 确定模型路径
if model_path is None:
model_path = os.getenv(
"EMBEDDING_MODEL_PATH",
"./data/models/Qwen3-Embedding-0.6B"
)
model_path = Path(model_path)
if not model_path.exists():
raise FileNotFoundError(
f"模型目录不存在:{model_path}\n"
"请先下载模型:\n"
" modelscope download --model 'Qwen/Qwen3-Embedding-0.6B' "
f"--local_dir '{model_path}'\n"
"或从Hugging Face下载:git lfs install && git clone "
f"https://huggingface.co/Qwen/Qwen3-Embedding-0.6B {model_path}"
)
# 确定设备
if device is None:
device = "cuda" if torch.cuda.is_available() else "cpu"
self.device = device
logger.info(f"加载Qwen3-Embedding模型:{model_path},设备:{device}")
# 加载 tokenizer:fast(Rust) 解析 tokenizer.json 需较新 tokenizers;
# 旧版本会报 ModelWrapper / untagged enum,回退到慢速 tokenizer 可恢复。
try:
self.tokenizer = AutoTokenizer.from_pretrained(
str(model_path), trust_remote_code=True
)
except Exception as e:
err = str(e).lower()
if "modelwrapper" in err or "untagged enum" in err:
logger.warning(
"快速 tokenizer 解析 tokenizer.json 失败(多为 tokenizers 过旧),"
"改用 use_fast=False:%s",
e,
)
self.tokenizer = AutoTokenizer.from_pretrained(
str(model_path), use_fast=False, trust_remote_code=True
)
else:
raise
try:
self.model = AutoModel.from_pretrained(
str(model_path), trust_remote_code=True
)
except ValueError as e:
msg = str(e)
if "qwen3" in msg.lower() or "does not recognize this architecture" in msg:
raise RuntimeError(
"当前 transformers 版本不支持 Qwen3(model_type=qwen3)。"
"请升级:pip install \"transformers>=4.51.0\" \"tokenizers>=0.21\""
) from e
raise
# 设置为评估模式并移动设备
self.model.eval()
self.model.to(device)
# 混合精度(仅GPU)
self.use_fp16 = use_fp16 and device != "cpu"
if self.use_fp16:
self.model.half()
# 嵌入维度
self.embedding_dim = self.model.config.hidden_size
logger.info(f"[OK] 模型加载完成,嵌入维度:{self.embedding_dim}")
def encode(
self,
texts: Union[str, List[str]],
batch_size: int = 32,
normalize: bool = True,
max_length: int = 8192,
show_progress: bool = False
) -> np.ndarray:
"""
编码文本为向量
Args:
texts: 单个文本或文本列表
batch_size: 批处理大小(根据显存调整)
normalize: 是否L2归一化(余弦相似度必需)
max_length: 最大序列长度(模型支持8192,建议512-1024平衡速度与精度)
show_progress: 是否显示进度条(需安装tqdm)
Returns:
numpy数组,shape=(len(texts), embedding_dim)
"""
if isinstance(texts, str):
texts = [texts]
if not texts:
return np.empty((0, self.embedding_dim), dtype=np.float32)
all_embeddings = []
# 可选进度条
iterator = range(0, len(texts), batch_size)
if show_progress:
try:
from tqdm import tqdm
iterator = tqdm(iterator, desc="Embedding")
except ImportError:
pass
for i in iterator:
batch = texts[i:i + batch_size]
# Tokenize
inputs = self.tokenizer(
batch,
padding=True,
truncation=True,
max_length=max_length,
return_tensors="pt"
).to(self.device)
# Inference
with torch.no_grad():
outputs = self.model(**inputs)
# Mean Pooling: 取序列维度的平均值
# outputs.last_hidden_state shape: (batch, seq_len, hidden_size)
embeddings = outputs.last_hidden_state.mean(dim=1)
# 转换为numpy(保持在CPU)
if self.device != "cpu":
embeddings = embeddings.cpu()
embeddings = embeddings.numpy()
if normalize:
# L2归一化(余弦相似度必需)
norms = np.linalg.norm(embeddings, axis=1, keepdims=True)
embeddings = embeddings / (norms + 1e-10)
all_embeddings.append(embeddings)
return np.vstack(all_embeddings).astype(np.float32)
def similarity(
self,
emb1: np.ndarray,
emb2: np.ndarray
) -> np.ndarray:
"""
计算两组embedding的余弦相似度
Args:
emb1: 第一组向量 (n, dim)
emb2: 第二组向量 (m, dim)
Returns:
相似度矩阵 (n, m),值域[-1, 1](若已归一化则为[0, 1])
"""
# 确保已归一化
return np.dot(emb1, emb2.T)
def encode_and_search(
self,
query: str,
documents: List[str],
top_k: int = 5
) -> List[dict]:
"""
便捷方法:编码查询并检索最相似的文档
Args:
query: 查询文本
documents: 候选文档列表
top_k: 返回前K个结果
Returns:
[{"score": float, "document": str, "index": int}, ...]
"""
query_emb = self.encode([query], normalize=True)
doc_embs = self.encode(documents, normalize=True)
scores = self.similarity(query_emb, doc_embs)[0]
# 获取top_k
top_indices = np.argsort(scores)[::-1][:top_k]
results = []
for idx in top_indices:
results.append({
"score": float(scores[idx]),
"document": documents[idx],
"index": int(idx)
})
return results
def _env_flag(name: str, default: str = "true") -> bool:
return os.getenv(name, default).strip().lower() in ("1", "true", "yes", "on")
class OpenAICompatibleRemoteEmbedding:
"""
通过 OpenAI 兼容接口获取文本向量(POST /v1/embeddings)。
环境变量(优先级:ModelScope → OpenAI 兼容 → DashScope):
- ModelScope:MODELSCOPE_API_KEY、可选 MODELSCOPE_BASE_URL(默认
https://api-inference.modelscope.cn/v1)、MODELSCOPE_EMBEDDING_MODEL
或 MODELSCOPE_MODEL、可选 MODELSCOPE_EMBEDDING_MAX_BATCH
- OpenAI 兼容:OPENAI_API_KEY、OPENAI_EMBEDDING_MODEL、可选 OPENAI_BASE_URL
(默认 https://api.openai.com/v1)、可选 OPENAI_EMBEDDING_MAX_BATCH
- DashScope:DASHSCOPE_API_KEY、DASHSCOPE_BASE_URL、DASHSCOPE_MODEL、
可选 DASHSCOPE_EMBEDDING_MAX_BATCH
可选 VECTOR_DIM:在首次请求前确定空列表返回的维度。
"""
def __init__(
self,
api_key: Optional[str] = None,
base_url: Optional[str] = None,
model: Optional[str] = None,
max_batch: Optional[int] = None,
provider_label: Optional[str] = None,
):
try:
from openai import OpenAI
except ImportError as e:
raise ImportError(
"使用远程 Embedding 需要安装 openai:pip install openai"
) from e
if api_key is not None and base_url is not None and model is not None:
cfg = _RemoteEmbeddingEnv(
api_key=api_key.strip(),
base_url=base_url.strip().rstrip("/"),
model=model.strip(),
max_batch=max(1, int(max_batch)) if max_batch is not None else 32,
label=provider_label or "custom",
)
else:
cfg = _remote_embedding_from_env()
self.api_key = cfg.api_key
self.base_url = cfg.base_url
self.model = cfg.model
self._api_max_batch = cfg.max_batch
self._provider_label = cfg.label
self._client = OpenAI(api_key=self.api_key, base_url=self.base_url)
vd = os.getenv("VECTOR_DIM", "").strip()
self._embedding_dim: Optional[int] = int(vd) if vd.isdigit() else None
logger.info(
"使用 %s Embedding API:model=%s,base_url=%s,max_batch=%s",
self._provider_label,
self.model,
self.base_url,
self._api_max_batch,
)
@property
def embedding_dim(self) -> int:
if self._embedding_dim is None:
raise RuntimeError(
"尚未获知向量维度:请先执行一次 encode,或在 .env 中设置 VECTOR_DIM"
)
return self._embedding_dim
def _set_dim_from_vector(self, vec: List[float]) -> None:
if self._embedding_dim is None:
self._embedding_dim = len(vec)
logger.info("[OK] Embedding 向量维度:%s", self._embedding_dim)
def encode(
self,
texts: Union[str, List[str]],
batch_size: int = 10,
normalize: bool = True,
max_length: int = 8192,
show_progress: bool = False,
) -> np.ndarray:
del max_length # API 侧截断,此处仅保持签名与本地实现一致
if isinstance(texts, str):
texts = [texts]
if not texts:
dim = self._embedding_dim
if dim is None:
vd = os.getenv("VECTOR_DIM", "").strip()
dim = int(vd) if vd.isdigit() else 1024
return np.empty((0, dim), dtype=np.float32)
# 无论调用方传多大,不能超过远端接口单次条数上限
step = max(1, min(int(batch_size), self._api_max_batch))
all_embeddings: List[np.ndarray] = []
iterator = range(0, len(texts), step)
if show_progress:
try:
from tqdm import tqdm
iterator = tqdm(iterator, desc="Embedding (API)")
except ImportError:
pass
for i in iterator:
batch = texts[i : i + step]
resp = self._client.embeddings.create(
model=self.model,
input=batch,
encoding_format="float",
)
rows = sorted(
[(d.index, d.embedding) for d in resp.data],
key=lambda x: x[0],
)
batch_embs = np.array([e for _, e in rows], dtype=np.float32)
if batch_embs.size > 0:
self._set_dim_from_vector(batch_embs[0].tolist())
if normalize:
norms = np.linalg.norm(batch_embs, axis=1, keepdims=True)
batch_embs = batch_embs / (norms + 1e-10)
all_embeddings.append(batch_embs)
return np.vstack(all_embeddings).astype(np.float32)
def similarity(self, emb1: np.ndarray, emb2: np.ndarray) -> np.ndarray:
return np.dot(emb1, emb2.T)
def encode_and_search(
self,
query: str,
documents: List[str],
top_k: int = 5,
) -> List[dict]:
query_emb = self.encode([query], normalize=True)
doc_embs = self.encode(documents, normalize=True)
scores = self.similarity(query_emb, doc_embs)[0]
top_indices = np.argsort(scores)[::-1][:top_k]
return [
{"score": float(scores[idx]), "document": documents[idx], "index": int(idx)}
for idx in top_indices
]
# 向后兼容旧名称
DashScopeOpenAIEmbedding = OpenAICompatibleRemoteEmbedding
# 全局单例(避免重复加载模型,节省显存/内存)
_embedding_instance: Optional[Any] = None
def get_embedder(
model_path: Optional[str] = None,
device: Optional[str] = None,
force_reload: bool = False,
) -> Any:
"""
获取 Embedding 单例:USE_LOCAL_EMBEDDING=true 时用本地 Qwen3,否则用远程
OpenAI 兼容 API(优先级见 OpenAICompatibleRemoteEmbedding)。
"""
global _embedding_instance
if force_reload or _embedding_instance is None:
if _env_flag("USE_LOCAL_EMBEDDING", "true"):
_embedding_instance = Qwen3Embedding(
model_path=model_path,
device=device,
)
else:
_embedding_instance = OpenAICompatibleRemoteEmbedding()
return _embedding_instance
def clear_embedder():
"""清空单例(用于测试或切换模型)"""
global _embedding_instance
_embedding_instance = None
import gc
gc.collect()
if _TRANSFORMERS_AVAILABLE:
import torch
if torch.cuda.is_available():
torch.cuda.empty_cache()
+356
View File
@@ -0,0 +1,356 @@
"""
Few-shot示例选择器 - 基于经验数据集动态选择相关示例
与 Schema 向量检索一致,使用 utils.embedding.get_embedder()(本地 Qwen3 或远程 OpenAI 兼容 API,
由 USE_LOCAL_EMBEDDING 及 OPENAI_* / MODELSCOPE_* / DASHSCOPE_* 等环境变量决定)。
用法:
from utils.fewshot_selector import FewShotSelector
selector = FewShotSelector("data/experiences/all_samples.jsonl")
examples = selector.select(question="查询2024年1月的销售额", top_k=3)
# 在Prompt中使用
prompt = f"{examples}\n当前问题:{question}\nSchema:{schema}"
"""
import json
import os
from pathlib import Path
from typing import List, Dict, Optional
from dataclasses import dataclass
import numpy as np
import logging
logger = logging.getLogger(__name__)
_DEFAULT_LOCAL_EMBED_PATH = "./data/models/Qwen3-Embedding-0.6B"
@dataclass
class ExperienceSample:
"""经验数据样本"""
qid: str
question_zh: str
question_en: Optional[str]
sql: str
explanation: str
rating: Optional[int]
tags: List[str]
difficulty: str
@classmethod
def from_dict(cls, data: dict) -> "ExperienceSample":
return cls(
qid=data.get("qid", ""),
question_zh=data.get("question_zh", ""),
question_en=data.get("question_en"),
sql=data.get("sql", ""),
explanation=data.get("explanation", ""),
rating=data.get("rating"),
tags=data.get("tags", []),
difficulty=data.get("difficulty", "medium")
)
def to_fewshot_format(self, include_explanation: bool = True) -> str:
"""转换为few-shot格式"""
result = f"问题:{self.question_zh}\nSQL:\n{self.sql}"
if include_explanation and self.explanation:
result += f"\n说明:{self.explanation[:200]}"
return result
def to_dict(self) -> dict:
return {
"qid": self.qid,
"question": self.question_zh,
"sql": self.sql,
"rating": self.rating,
"tags": self.tags,
"difficulty": self.difficulty
}
class FewShotSelector:
"""
Few-shot示例选择器
根据用户问题,从经验数据集中检索最相似的示例,
用于增强Prompt,提升LLM生成质量。
"""
def __init__(
self,
samples_path: str,
embedding_model_path: Optional[str] = None,
use_cache: bool = True,
):
"""
Args:
samples_path: 样本JSONL文件路径
embedding_model_path: 本地 Embedding 模型目录;None 时用环境变量
EMBEDDING_MODEL_PATH(仅 USE_LOCAL_EMBEDDING=true 时有效)
use_cache: 是否缓存样本向量(按向量维度分文件,换模型会自动重建)
"""
self.samples_path = Path(samples_path)
self.samples: List[ExperienceSample] = []
self._embedder = None
self.embeddings: Optional[np.ndarray] = None
self.use_cache = use_cache
self.cache_path: Optional[Path] = None
self._embedding_model_path = (
embedding_model_path
if embedding_model_path is not None
else os.getenv("EMBEDDING_MODEL_PATH", _DEFAULT_LOCAL_EMBED_PATH).strip()
)
self._load_samples()
self._build_index()
def _load_samples(self):
"""加载样本数据"""
if not self.samples_path.exists():
raise FileNotFoundError(f"样本文件不存在: {self.samples_path}")
logger.info(f"加载样本: {self.samples_path}")
with self.samples_path.open('r', encoding='utf-8') as f:
for line in f:
data = json.loads(line.strip())
self.samples.append(ExperienceSample.from_dict(data))
logger.info(f"[OK] 加载 {len(self.samples)} 个样本")
def _build_index(self):
"""用项目统一 Embedder 构建语义索引"""
from utils.embedding import get_embedder
self._embedder = get_embedder(self._embedding_model_path)
probe = self._embedder.encode(
[" "],
batch_size=1,
normalize=True,
show_progress=False,
)
dim = int(probe.shape[1])
self.cache_path = (
self.samples_path.parent / f"{self.samples_path.stem}.fewshot_dim{dim}.npy"
)
if self.use_cache and self.cache_path.exists():
try:
self.embeddings = np.load(self.cache_path)
if (
self.embeddings.shape[0] == len(self.samples)
and self.embeddings.shape[1] == dim
):
logger.info(f"[OK] 加载 Few-shot 向量缓存: {self.cache_path}")
return
except Exception as e:
logger.warning(f"Few-shot 缓存加载失败: {e},将重新计算")
# 远程 API 通常不接受空字符串作 input
questions = [
(s.question_zh or "").strip() or " "
for s in self.samples
]
if not questions:
self.embeddings = np.empty((0, dim), dtype=np.float32)
return
logger.info(f"计算 {len(questions)} 个 Few-shot 样本向量...")
self.embeddings = self._embedder.encode(
questions,
batch_size=min(32, len(questions)),
normalize=True,
show_progress=True,
)
if self.use_cache and self.cache_path is not None:
np.save(self.cache_path, self.embeddings)
logger.info(f"[OK] Few-shot 向量已缓存: {self.cache_path}")
def select(
self,
question: str,
top_k: int = 3,
min_rating: Optional[int] = None,
required_tags: Optional[List[str]] = None,
max_difficulty: str = "hard",
exclude_qids: Optional[List[str]] = None
) -> List[ExperienceSample]:
"""
选择最相关的few-shot示例
Args:
question: 用户问题
top_k: 返回示例数量
min_rating: 最低评分(None表示不限制)
required_tags: 必须包含的标签(如["aggregation", "join"])
max_difficulty: 最大难度(过滤更难的示例)
exclude_qids: 排除的QID(避免与当前问题相同)
Returns:
排序后的示例列表(最相关优先)
"""
if self._embedder is None or self.embeddings is None:
logger.error("Few-shot 索引未初始化")
return []
if len(self.samples) == 0:
return []
q_emb = self._embedder.encode(
[question],
batch_size=1,
normalize=True,
show_progress=False,
)[0]
scores = np.dot(self.embeddings, q_emb)
candidates = []
for idx, (score, sample) in enumerate(zip(scores, self.samples)):
if exclude_qids and sample.qid in exclude_qids:
continue
if min_rating and sample.rating and sample.rating < min_rating:
continue
if max_difficulty == "easy" and sample.difficulty != "easy":
continue
if max_difficulty == "medium" and sample.difficulty == "hard":
continue
if required_tags and not all(tag in sample.tags for tag in required_tags):
continue
candidates.append((idx, score, sample))
candidates.sort(key=lambda x: -x[1])
selected = [sample for _, _, sample in candidates[:top_k]]
logger.info(
f"Few-shot选择: 问题='{question[:30]}...' "
f"→ 选中{len(selected)}个示例 (top_k={top_k}, min_rating={min_rating})"
)
for s in selected:
logger.debug(
f" [{s.qid}] {s.question_zh[:50]}... (rating={s.rating}, tags={s.tags[:3]})"
)
return selected
def get_examples_prompt(
self,
question: str,
top_k: int = 3,
min_rating: int = 7,
**kwargs
) -> str:
"""
生成few-shot prompt片段
Returns:
格式化的示例字符串,可直接插入Prompt
"""
examples = self.select(question, top_k=top_k, min_rating=min_rating, **kwargs)
if not examples:
return ""
lines = ["以下为相似问题的参考SQL示例:\n"]
for i, ex in enumerate(examples, 1):
lines.append(f"示例{i}:")
lines.append(f"问题:{ex.question_zh}")
lines.append(f"SQL:\n{ex.sql}")
if ex.explanation:
lines.append(f"说明:{ex.explanation[:150]}...")
lines.append("") # 空行分隔
return "\n".join(lines)
def get_tagged_examples(self, tags: List[str], top_k_per_tag: int = 2) -> str:
"""获取特定标签的示例"""
tagged_samples = []
for sample in self.samples:
if any(tag in sample.tags for tag in tags):
tagged_samples.append(sample)
tagged_samples.sort(key=lambda s: -(s.rating or 0))
selected = tagged_samples[:top_k_per_tag * len(tags)]
lines = [f"# {tags} 相关示例\n"]
for ex in selected:
lines.append(f"## {ex.qid}. {ex.question_zh[:50]}")
lines.append(f"评分: {ex.rating}/10")
lines.append(f"标签: {', '.join(ex.tags)}")
lines.append(f"```sql\n{ex.sql}\n```\n")
return "\n".join(lines)
def get_stats(self) -> Dict:
"""获取数据集统计"""
stats = {
"total": len(self.samples),
"by_rating": {},
"by_difficulty": {},
"by_tag": {},
"avg_rating": 0.0
}
ratings = [s.rating for s in self.samples if s.rating]
if ratings:
stats["avg_rating"] = sum(ratings) / len(ratings)
for r in range(1, 11):
stats["by_rating"][r] = sum(1 for s in self.samples if s.rating == r)
for diff in ["easy", "medium", "hard"]:
stats["by_difficulty"][diff] = sum(
1 for s in self.samples if s.difficulty == diff
)
tag_counts = {}
for s in self.samples:
for tag in s.tags:
tag_counts[tag] = tag_counts.get(tag, 0) + 1
stats["by_tag"] = tag_counts
return stats
def load_fewshot_selector() -> FewShotSelector:
"""加载默认的few-shot选择器"""
default_path = Path(__file__).resolve().parent.parent / "data" / "experiences" / "all_samples.jsonl"
return FewShotSelector(str(default_path))
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Few-shot示例选择器")
parser.add_argument("--samples", default="data/experiences/all_samples.jsonl")
parser.add_argument("--question", help="测试问题")
parser.add_argument("--top-k", type=int, default=3)
parser.add_argument("--min-rating", type=int, default=7)
parser.add_argument("--stats", action="store_true", help="显示数据集统计")
args = parser.parse_args()
selector = FewShotSelector(args.samples)
if args.stats:
stats = selector.get_stats()
print("📊 数据集统计:")
print(f" 总样本: {stats['total']}")
print(f" 平均评分: {stats['avg_rating']:.1f}")
print(f" 难度分布: {stats['by_difficulty']}")
print(f"\n Top 10 标签:")
sorted_tags = sorted(stats["by_tag"].items(), key=lambda x: -x[1])[:10]
for tag, count in sorted_tags:
print(f" {tag}: {count}")
elif args.question:
examples = selector.select(args.question, top_k=args.top_k, min_rating=args.min_rating)
print(f"\n为问题 '{args.question}' 选择的示例:\n")
for ex in examples:
print(f"[{ex.qid}] 评分:{ex.rating} 难度:{ex.difficulty}")
print(f"问题: {ex.question_zh}")
print(f"SQL:\n{ex.sql}\n")
else:
print("请指定 --question 或 --stats")
+364
View File
@@ -0,0 +1,364 @@
"""
SQL 解析与验证工具(基于 sqlglot)
"""
import logging
import re
from typing import List, Tuple, Optional, Dict
import sqlglot
from sqlglot import exp, parse_one, ParseError
from schema.manager import SchemaManager
from schema.models import Table, Column
logger = logging.getLogger(__name__)
def validate_sql_syntax(sql: str, dialect: str = "tsql") -> Tuple[bool, List[str]]:
"""
验证SQL语法是否正确
Args:
sql: SQL语句
dialect: SQL方言
Returns:
(是否有效, 错误信息列表)
"""
errors = []
try:
# 尝试解析
parsed = parse_one(sql, dialect=dialect)
if parsed is None:
errors.append("SQL解析返回空结果")
return False, errors
# 检查是否为只读查询(SELECT/CTE/SHOW等)
# 动态获取可用表达式类型(兼容不同sqlglot版本)
readable_ops = [exp.Select, exp.Union, exp.Intersect, exp.Except, exp.With]
# 可选:添加 Show, Describe, Explain(如果存在)
for op_name in ['Show', 'Describe', 'Explain']:
if hasattr(exp, op_name):
readable_ops.append(getattr(exp, op_name))
if not isinstance(parsed, tuple(readable_ops)):
op_type = type(parsed).__name__
errors.append(f"非查询操作({op_type}),只允许SELECT等只读语句")
return True, []
except ParseError as e:
errors.append(f"SQL语法错误: {str(e)}")
return False, errors
except Exception as e:
errors.append(f"解析异常: {str(e)}")
return False, errors
def extract_tables_from_sql(sql: str, dialect: str = "tsql") -> List[str]:
"""
从SQL中提取所有表名
Args:
sql: SQL语句
dialect: SQL方言
Returns:
表名列表(去重)
"""
try:
parsed = parse_one(sql, dialect=dialect)
tables = []
# 遍历AST查找所有表名
for node in parsed.walk():
if isinstance(node, exp.Table):
table_name = node.name
if table_name and table_name not in tables:
tables.append(table_name)
return tables
except Exception as e:
logger.warning(f"提取表名失败: {e}")
return []
def build_table_alias_map(parsed: exp.Expression) -> Dict[str, str]:
"""
从已解析的 AST 构建「别名/表名 -> 物理表名」映射。
FROM T a 时 a -> T,且 T -> T,便于将 a.col 解析到表 T 的列。
"""
alias_map: Dict[str, str] = {}
for node in parsed.walk():
if not isinstance(node, exp.Table):
continue
physical = node.name
if not physical:
continue
alias_map[physical] = physical
talias = node.args.get("alias")
if talias is not None:
aname = talias.name
if aname:
alias_map[aname] = physical
return alias_map
def extract_columns_from_sql(sql: str, dialect: str = "tsql") -> List[Tuple[str, str]]:
"""
从SQL中提取所有字段引用(表.字段)
Args:
sql: SQL语句
dialect: SQL方言
Returns:
[(表名, 字段名), ...] 列表
"""
columns = []
try:
parsed = parse_one(sql, dialect=dialect)
for node in parsed.walk():
if isinstance(node, exp.Column):
table_name = node.table
col_name = node.name
if table_name and col_name:
columns.append((table_name, col_name))
return columns
except Exception as e:
logger.warning(f"提取字段失败: {e}")
return []
def validate_schema_consistency(
sql: str,
schema_manager: SchemaManager,
dialect: str = "tsql"
) -> Tuple[bool, List[str]]:
"""
验证SQL与Schema的一致性
检查:
1. 所有表名存在于Schema
2. 所有字段名属于对应的表
3. JOIN条件字段存在且类型兼容
Args:
sql: SQL语句
schema_manager: Schema管理器
dialect: SQL方言
Returns:
(是否一致, 错误信息列表)
"""
errors = []
try:
parsed = parse_one(sql, dialect=dialect)
except Exception as e:
logger.debug(f"Schema一致性检查跳过(解析失败): {e}")
return True, []
alias_map = build_table_alias_map(parsed)
tables_used: List[str] = []
for node in parsed.walk():
if isinstance(node, exp.Table):
tname = node.name
if tname and tname not in tables_used:
tables_used.append(tname)
columns_used: List[Tuple[str, str]] = []
for node in parsed.walk():
if isinstance(node, exp.Column):
tref, cname = node.table, node.name
if tref and cname:
columns_used.append((tref, cname))
# 检查表存在性
for tbl in tables_used:
if not schema_manager.get_table(tbl):
errors.append(f"表不存在: '{tbl}'")
# 检查字段存在性(表引用可为物理表名或别名)
for tbl_name, col_name in columns_used:
physical = alias_map.get(tbl_name, tbl_name)
table = schema_manager.get_table(physical)
if not table:
errors.append(
f"字段不存在: '{tbl_name}.{col_name}'"
f"(无法将表引用解析到已加载Schema中的表)"
)
continue
col_names = [c.name for c in table.columns]
if col_name not in col_names:
errors.append(
f"字段不存在: '{tbl_name}.{col_name}'"
f"(表 '{physical}' 可用字段: {col_names[:5]}...)"
)
# 检查JOIN条件(外键匹配)
try:
for join in parsed.find_all(exp.Join):
# 解析ON条件
on_condition = join.args.get("on")
if on_condition:
# 检查ON条件中涉及的字段
for eq in on_condition.find_all(exp.EQ):
left = eq.left
right = eq.right
# 提取左右两边的表.字段
for side in [left, right]:
if isinstance(side, exp.Column):
tbl = side.table
col = side.name
physical = alias_map.get(tbl, tbl)
table = schema_manager.get_table(physical)
if table and col not in [c.name for c in table.columns]:
errors.append(f"JOIN条件字段不存在: {tbl}.{col}")
except Exception as e:
logger.debug(f"JOIN条件检查异常: {e}")
return len(errors) == 0, errors
def rewrite_mysql_builtins_for_tsql(sql: str) -> str:
"""
模型在 T-SQL 目标下仍常输出 MySQL 函数;sqlglot 转写也可能遗漏。
SQL Server 无 CURDATE()/NOW(),需替换为 GETDATE 族。
"""
if not sql:
return sql
out = sql
out = re.sub(
r"\bCURDATE\s*\(\s*\)",
"CAST(GETDATE() AS DATE)",
out,
flags=re.IGNORECASE,
)
out = re.sub(
r"\bCURRENT_DATE\b",
"CAST(GETDATE() AS DATE)",
out,
flags=re.IGNORECASE,
)
out = re.sub(r"\bNOW\s*\(\s*\)", "GETDATE()", out, flags=re.IGNORECASE)
return out
def normalize_sql_for_dialect(sql: str, dialect: str) -> str:
"""
将模型输出的 SQL 规范为目标方言。
对于 T-SQL,主要进行 MySQL 函数替换(因为模型仍可能输出 CURDATE() 等)。
"""
sql = (sql or "").strip()
if not sql:
return sql
# 如果目标是 T-SQL,只做函数名替换,不再用 sqlglot 转写
if dialect == "tsql":
return rewrite_mysql_builtins_for_tsql(sql)
return sql
def format_sql(sql: str, dialect: str = "tsql", indent: int = 2) -> str:
"""
格式化SQL(可读性)
Args:
sql: SQL语句
dialect: SQL方言
indent: 缩进空格数
Returns:
格式化后的SQL
"""
try:
parsed = parse_one(sql, dialect=dialect)
return parsed.sql(dialect=dialect, pretty=True, indent=indent)
except Exception as e:
logger.warning(f"SQL格式化失败: {e}")
return sql
def normalize_sql(sql: str, dialect: str = "tsql") -> str:
"""
标准化SQL(用于比较去重)
去除多余空格、统一引号、移除注释等
Args:
sql: SQL语句
dialect: SQL方言
Returns:
标准化后的SQL
"""
try:
# 解析后重新生成(会规范化格式)
parsed = parse_one(sql, dialect=dialect)
normalized = parsed.sql(dialect=dialect, pretty=False)
# 转换为大写关键词
return normalized.upper()
except Exception:
# 降级:简单处理
import re
# 移除多余空格
sql = re.sub(r'\s+', ' ', sql.strip())
# 移除注释
sql = re.sub(r'--.*?$', '', sql, flags=re.MULTILINE)
sql = re.sub(r'/\*.*?\*/', '', sql, flags=re.DOTALL)
return sql.upper()
def count_joins(sql: str, dialect: str = "tsql") -> int:
"""统计JOIN数量"""
try:
parsed = parse_one(sql, dialect=dialect)
joins = list(parsed.find_all(exp.Join))
return len(joins)
except Exception:
return 0
def has_subquery(sql: str, dialect: str = "tsql") -> bool:
"""检查是否包含子查询"""
try:
parsed = parse_one(sql, dialect=dialect)
# 检查嵌套的SELECT
for select in parsed.find_all(exp.Select):
if select is not parsed: # 不是最外层的SELECT
return True
return False
except Exception:
return False
def get_query_complexity(sql: str, dialect: str = "tsql") -> Dict[str, int]:
"""
评估查询复杂度
Returns:
复杂度指标字典
"""
try:
parsed = parse_one(sql, dialect=dialect)
return {
"join_count": len(list(parsed.find_all(exp.Join))),
"subquery_count": len([s for s in parsed.find_all(exp.Select) if s is not parsed]),
"where_conditions": len(list(parsed.find_all(exp.Predicate))),
"aggregation_functions": len(list(parsed.find_all(exp.AggFunc))),
"column_count": len(list(parsed.find_all(exp.Column))),
}
except Exception as e:
logger.warning(f"复杂度评估失败: {e}")
return {}
+346
View File
@@ -0,0 +1,346 @@
"""
SQL 验证工具集
"""
import re
import logging
from typing import Tuple, List, Dict
logger = logging.getLogger(__name__)
# 危险操作关键词(除非明确允许)
DANGEROUS_KEYWORDS = [
"DROP", "DELETE", "UPDATE", "INSERT", "ALTER", "TRUNCATE",
"CREATE", "DROP DATABASE", "DROP TABLE", "DROP INDEX",
"GRANT", "REVOKE", "PURGE", "FLUSH", "KILL"
]
# 允许的操作(仅查询)
ALLOWED_KEYWORDS = [
"SELECT", "WITH", "FROM", "WHERE", "JOIN", "LEFT JOIN", "RIGHT JOIN",
"INNER JOIN", "OUTER JOIN", "ON", "USING", "GROUP BY", "HAVING",
"ORDER BY", "LIMIT", "OFFSET", "UNION", "UNION ALL", "EXCEPT", "INTERSECT",
"AS", "CASE", "WHEN", "THEN", "ELSE", "END",
"COUNT", "SUM", "AVG", "MIN", "MAX", "DISTINCT",
"AND", "OR", "NOT", "IN", "EXISTS", "BETWEEN", "LIKE", "IS NULL", "IS NOT NULL",
"CAST", "COALESCE", "NULLIF", "IFNULL",
"DATE", "TIME", "TIMESTAMP", "EXTRACT", "DATE_FORMAT", "STR_TO_DATE",
"CURRENT_DATE", "CURRENT_TIMESTAMP",
]
def check_dangerous_operations(sql: str) -> Tuple[bool, List[str]]:
"""
检查SQL是否包含危险操作
Args:
sql: SQL语句(大小写不敏感)
Returns:
(是否安全, 危险关键词列表)
"""
sql_upper = sql.upper()
found_dangers = []
for keyword in DANGEROUS_KEYWORDS:
# 使用正则避免部分匹配(如"DROP"不应匹配"DROPOUT")
pattern = r'\b' + re.escape(keyword) + r'\b'
if re.search(pattern, sql_upper):
found_dangers.append(keyword)
is_safe = len(found_dangers) == 0
if not is_safe:
logger.warning(f"检测到危险操作: {found_dangers}")
return is_safe, found_dangers
def validate_no_dml(sql: str) -> Tuple[bool, str]:
"""
验证SQL不是DML/DDL操作(仅允许SELECT等查询)
Returns:
(是否通过, 错误消息)
"""
sql_upper = sql.strip().upper()
# 检查是否以危险关键词开头
first_word = sql_upper.split()[0] if sql_upper.split() else ""
if first_word in ["INSERT", "UPDATE", "DELETE", "DROP", "ALTER", "CREATE", "TRUNCATE"]:
return False, f"禁止的操作: {first_word}"
is_safe, dangers = check_dangerous_operations(sql)
if not is_safe:
return False, f"SQL包含危险操作: {', '.join(dangers)}"
return True, ""
def check_sql_injection_patterns(sql: str) -> List[str]:
"""
检查明显的SQL注入模式
Args:
sql: SQL语句
Returns:
发现的注入模式列表
"""
patterns = {
"union_all_injection": r"UNION\s+ALL\s+SELECT",
"union_injection": r"UNION\s+SELECT",
"comment_injection": r"(--|\#|/\*).*SELECT",
"semicolon_injection": r";\s*(DROP|DELETE|UPDATE|INSERT)",
"or_true_condition": r"OR\s+['\"]?\s*1\s*['\"]?\s*=\s*1",
"always_true": r"1\s*=\s*1",
}
findings = []
sql_lower = sql.lower()
for name, pattern in patterns.items():
if re.search(pattern, sql, re.IGNORECASE):
findings.append(name)
return findings
def validate_aggregation_groupby(sql: str, dialect: str = "tsql") -> Tuple[bool, List[str]]:
"""
验证聚合查询的GROUP BY正确性
检查:SELECT中的非聚合字段是否都在GROUP BY中
Args:
sql: SQL语句
dialect: SQL方言
Returns:
(是否有效, 错误列表)
"""
from utils.sql_parser import parse_one, exp
errors = []
try:
parsed = parse_one(sql, dialect=dialect)
# 只检查SELECT语句
if not isinstance(parsed, exp.Select):
return True, []
# 获取SELECT列表中的表达式
select_exprs = parsed.expressions
# 获取GROUP BY字段
group_by = parsed.args.get("group")
if not group_by:
# 没有GROUP BY但有聚合函数,通常是错误的
has_agg = any(
expr.find(exp.AggFunc) is not None
for expr in select_exprs
)
if has_agg:
errors.append("包含聚合函数但缺少GROUP BY子句")
return len(errors) == 0, errors
group_by_exprs = group_by.expressions
# 提取GROUP BY的字段名(简单处理)
group_by_cols = set()
for expr in group_by_exprs:
if isinstance(expr, exp.Column):
group_by_cols.add(expr.name)
elif isinstance(expr, exp.Ordered):
# GROUP BY x ASC/DESC
this = expr.this
if isinstance(this, exp.Column):
group_by_cols.add(this.name)
# 检查每个SELECT表达式
for expr in select_exprs:
# 如果是聚合函数,跳过
if expr.find(exp.AggFunc):
continue
# 如果是字面量或表达式,跳过
if isinstance(expr, exp.Literal):
continue
# 如果是列引用,检查是否在GROUP BY中
if isinstance(expr, exp.Column):
col_name = expr.name
if col_name not in group_by_cols:
errors.append(
f"字段 '{col_name}' 在SELECT中但不在GROUP BY中"
)
elif isinstance(expr, exp.Alias):
# 别名: column AS alias
this = expr.this
if isinstance(this, exp.Column):
col_name = this.name
if col_name not in group_by_cols:
errors.append(
f"字段 '{col_name}' (别名为'{expr.alias}') 在SELECT中但不在GROUP BY中"
)
except Exception as e:
logger.debug(f"GROUP BY验证异常: {e}")
return len(errors) == 0, errors
def check_join_conditions(sql: str, dialect: str = "tsql") -> List[str]:
"""
检查JOIN条件是否完整
Args:
sql: SQL语句
dialect: SQL方言
Returns:
问题列表(空表示无问题)
"""
from utils.sql_parser import parse_one, exp
issues = []
try:
parsed = parse_one(sql, dialect=dialect)
# 遍历所有JOIN
for join in parsed.find_all(exp.Join):
# 检查是否有ON条件
on_condition = join.args.get("on")
if on_condition is None:
# 检查是否使用USING
using = join.args.get("using")
if using is None:
issues.append("JOIN缺少ON条件")
else:
# ON条件为空表达式
if isinstance(on_condition, exp.Empty):
issues.append("JOIN的ON条件为空")
except Exception as e:
logger.debug(f"JOIN条件检查异常: {e}")
return issues
def validate_order_by_fields(
sql: str,
schema_manager,
dialect: str = "tsql"
) -> List[str]:
"""
验证ORDER BY字段是否存在于对应表中
Args:
sql: SQL语句
schema_manager: Schema管理器
dialect: SQL方言
Returns:
问题列表
"""
from utils.sql_parser import parse_one, exp
issues = []
try:
parsed = parse_one(sql, dialect=dialect)
order = parsed.args.get("order")
if order:
for ordered in order.expressions:
expr = ordered.this
# 提取字段和表
if isinstance(expr, exp.Column):
tbl_name = expr.table
col_name = expr.name
if tbl_name:
table = schema_manager.get_table(tbl_name)
if table:
col_names = [c.name for c in table.columns]
if col_name not in col_names:
issues.append(
f"ORDER BY字段不存在: {tbl_name}.{col_name}"
)
except Exception as e:
logger.debug(f"ORDER BY验证异常: {e}")
return issues
def full_validation_pipeline(
sql: str,
schema_manager,
dialect: str = "tsql",
check_dangerous: bool = True
) -> Dict:
"""
完整验证流水线
Args:
sql: SQL语句
schema_manager: Schema管理器
dialect: SQL方言
check_dangerous: 是否检查危险操作
Returns:
验证结果字典
"""
result = {
"valid": True,
"errors": [],
"warnings": [],
"suggestions": []
}
# 1. 语法验证
syntax_ok, syntax_errors = validate_sql_syntax(sql, dialect)
if not syntax_ok:
result["valid"] = False
result["errors"].extend(syntax_errors)
# 2. 危险操作检查
if check_dangerous:
safe, dangers = check_dangerous_operations(sql)
if not safe:
result["valid"] = False
result["errors"].append(f"包含危险操作: {', '.join(dangers)}")
# 3. Schema一致性验证
schema_ok, schema_errors = validate_schema_consistency(sql, schema_manager, dialect)
if not schema_ok:
result["valid"] = False
result["errors"].extend(schema_errors)
# 4. GROUP BY验证
groupby_ok, groupby_errors = validate_aggregation_groupby(sql, dialect)
if not groupby_ok:
result["valid"] = False
result["errors"].extend(groupby_errors)
# 5. JOIN条件验证
join_issues = check_join_conditions(sql, dialect)
if join_issues:
result["valid"] = False
result["errors"].extend(join_issues)
# 6. ORDER BY验证
order_issues = validate_order_by_fields(sql, schema_manager, dialect)
if order_issues:
result["warnings"].extend(order_issues)
# 7. SQL注入模式检查(警告)
injection_patterns = check_sql_injection_patterns(sql)
if injection_patterns:
result["warnings"].append(f"检测到可疑模式: {', '.join(injection_patterns)}")
return result