feat: improve generate sql template

1.Add parameter: GENERATE_SQL_QUERY_LIMIT_ENABLED (default value is True to control data return Limit 1000 rows)
2.Use different SQL example templates based on different data sources.
This commit is contained in:
ulleo
2025-10-15 18:34:47 +08:00
committed by ulleo
parent 67f446e858
commit 55fb063f6e
18 changed files with 1085 additions and 92 deletions
+22 -4
View File
@@ -1,6 +1,6 @@
from datetime import datetime
from enum import Enum
from typing import List, Optional
from typing import List, Optional, Union
from fastapi import Body
from pydantic import BaseModel
@@ -9,13 +9,14 @@ from sqlalchemy import Enum as SQLAlchemyEnum
from sqlalchemy.dialects.postgresql import JSONB
from sqlmodel import SQLModel, Field
from apps.db.constant import DB
from apps.template.filter.generator import get_permissions_template
from apps.template.generate_analysis.generator import get_analysis_template
from apps.template.generate_chart.generator import get_chart_template
from apps.template.generate_dynamic.generator import get_dynamic_template
from apps.template.generate_guess_question.generator import get_guess_question_template
from apps.template.generate_predict.generator import get_predict_template
from apps.template.generate_sql.generator import get_sql_template
from apps.template.generate_sql.generator import get_sql_template, get_sql_example_template
from apps.template.select_datasource.generator import get_datasource_template
@@ -182,10 +183,27 @@ class AiModelQuestion(BaseModel):
custom_prompt: str = ""
error_msg: str = ""
def sql_sys_question(self):
def sql_sys_question(self, db_type: Union[str, DB], enable_query_limit: bool = True):
_sql_template = get_sql_example_template(db_type)
_base_sql_rules = _sql_template['quot_rule'] + _sql_template['limit_rule'] + _sql_template['other_rule']
_query_limit = get_sql_template()['query_limit'] if enable_query_limit else ''
_sql_examples = _sql_template['basic_example']
_example_engine = _sql_template['example_engine']
_example_answer_1 = _sql_template['example_answer_1_with_limit'] if enable_query_limit else _sql_template[
'example_answer_1']
_example_answer_2 = _sql_template['example_answer_2_with_limit'] if enable_query_limit else _sql_template[
'example_answer_2']
_example_answer_3 = _sql_template['example_answer_3_with_limit'] if enable_query_limit else _sql_template[
'example_answer_3']
return get_sql_template()['system'].format(engine=self.engine, schema=self.db_schema, question=self.question,
lang=self.lang, terminologies=self.terminologies,
data_training=self.data_training, custom_prompt=self.custom_prompt)
data_training=self.data_training, custom_prompt=self.custom_prompt,
base_sql_rules=_base_sql_rules, query_limit=_query_limit,
basic_sql_examples=_sql_examples,
example_engine=_example_engine,
example_answer_1=_example_answer_1,
example_answer_2=_example_answer_2,
example_answer_3=_example_answer_3)
def sql_user_question(self, current_time: str):
return get_sql_template()['user'].format(engine=self.engine, schema=self.db_schema, question=self.question,
+2 -1
View File
@@ -171,7 +171,8 @@ class LLMService:
self.sql_message = []
# add sys prompt
self.sql_message.append(SystemMessage(content=self.chat_question.sql_sys_question()))
self.sql_message.append(SystemMessage(
content=self.chat_question.sql_sys_question(self.ds.type, settings.GENERATE_SQL_QUERY_LIMIT_ENABLED)))
if last_sql_messages is not None and len(last_sql_messages) > 0:
# limit count
for last_sql_message in last_sql_messages[count_limit:]:
+19 -15
View File
@@ -13,29 +13,33 @@ class ConnectType(Enum):
class DB(Enum):
mysql = ('mysql', 'MySQL', '`', '`', ConnectType.sqlalchemy)
sqlServer = ('sqlServer', 'Microsoft SQL Server', '[', ']', ConnectType.sqlalchemy)
pg = ('pg', 'PostgreSQL', '"', '"', ConnectType.sqlalchemy)
excel = ('excel', 'Excel/CSV', '"', '"', ConnectType.sqlalchemy)
oracle = ('oracle', 'Oracle', '"', '"', ConnectType.sqlalchemy)
ck = ('ck', 'ClickHouse', '"', '"', ConnectType.sqlalchemy)
dm = ('dm', '达梦', '"', '"', ConnectType.py_driver)
doris = ('doris', 'Apache Doris', '`', '`', ConnectType.py_driver)
redshift = ('redshift', 'AWS Redshift', '"', '"', ConnectType.py_driver)
es = ('es', 'Elasticsearch', '"', '"', ConnectType.py_driver)
kingbase = ('kingbase', 'Kingbase', '"', '"', ConnectType.py_driver)
starrocks = ('starrocks', 'StarRocks', '`', '`', ConnectType.py_driver)
excel = ('excel', 'Excel/CSV', '"', '"', ConnectType.sqlalchemy, 'PostgreSQL')
redshift = ('redshift', 'AWS Redshift', '"', '"', ConnectType.py_driver, 'AWS_Redshift')
ck = ('ck', 'ClickHouse', '"', '"', ConnectType.sqlalchemy, 'ClickHouse')
dm = ('dm', '达梦', '"', '"', ConnectType.py_driver, 'DM')
doris = ('doris', 'Apache Doris', '`', '`', ConnectType.py_driver, 'Doris')
es = ('es', 'Elasticsearch', '"', '"', ConnectType.py_driver, 'Elasticsearch')
kingbase = ('kingbase', 'Kingbase', '"', '"', ConnectType.py_driver, 'Kingbase')
sqlServer = ('sqlServer', 'Microsoft SQL Server', '[', ']', ConnectType.sqlalchemy, 'Microsoft_SQL_Server')
mysql = ('mysql', 'MySQL', '`', '`', ConnectType.sqlalchemy, 'MySQL')
oracle = ('oracle', 'Oracle', '"', '"', ConnectType.sqlalchemy, 'Oracle')
pg = ('pg', 'PostgreSQL', '"', '"', ConnectType.sqlalchemy, 'PostgreSQL')
starrocks = ('starrocks', 'StarRocks', '`', '`', ConnectType.py_driver, 'StarRocks')
def __init__(self, type, db_name, prefix, suffix, connect_type: ConnectType):
def __init__(self, type, db_name, prefix, suffix, connect_type: ConnectType, template_name: str):
self.type = type
self.db_name = db_name
self.prefix = prefix
self.suffix = suffix
self.connect_type = connect_type
self.template_name = template_name
@classmethod
def get_db(cls, type):
def get_db(cls, type, default_if_none=False):
for db in cls:
if db.type == type:
return db
raise ValueError(f"Invalid db type: {type}")
if default_if_none:
return DB.pg
else:
raise ValueError(f"Invalid db type: {type}")
@@ -1,6 +1,14 @@
from apps.template.template import get_base_template
from typing import Union
from apps.db.constant import DB
from apps.template.template import get_base_template, get_sql_template as get_base_sql_template
def get_sql_template():
template = get_base_template()
return template['template']['sql']
def get_sql_example_template(db_type: Union[str, DB]):
template = get_base_sql_template(db_type)
return template['template']
+57 -8
View File
@@ -1,15 +1,64 @@
import yaml
from pathlib import Path
from functools import cache
from typing import Union
base_template = None
from apps.db.constant import DB
# 基础路径配置
PROJECT_ROOT = Path(__file__).parent.parent.parent
TEMPLATES_DIR = PROJECT_ROOT / 'templates'
BASE_TEMPLATE_PATH = TEMPLATES_DIR / 'template.yaml'
SQL_TEMPLATES_DIR = TEMPLATES_DIR / 'sql_examples'
def load():
with open('./template.yaml', 'r', encoding='utf-8') as f:
global base_template
base_template = yaml.load(f, Loader=yaml.SafeLoader)
@cache
def _load_template_file(file_path: Path):
"""内部函数:加载并解析YAML文件"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
return yaml.safe_load(f)
except FileNotFoundError:
raise FileNotFoundError(f"Template file not found at {file_path}")
except yaml.YAMLError as e:
raise ValueError(f"Error parsing YAML file {file_path}: {e}")
def get_base_template():
if not base_template:
load()
return base_template
"""获取基础模板(自动缓存)"""
return _load_template_file(BASE_TEMPLATE_PATH)
def get_sql_template(db_type: Union[str, DB]):
# 处理输入参数
if isinstance(db_type, str):
# 如果是字符串,查找对应的枚举值,找不到则使用默认的 DB.pg
db_enum = DB.get_db(db_type, default_if_none=True)
elif isinstance(db_type, DB):
db_enum = db_type
else:
db_enum = DB.pg
# 使用 template_name 作为文件名
template_path = SQL_TEMPLATES_DIR / f"{db_enum.template_name}.yaml"
return _load_template_file(template_path)
def get_all_sql_templates():
"""获取所有支持的数据库模板"""
templates = {}
for db in DB:
try:
templates[db.type] = get_sql_template(db)
except FileNotFoundError:
# 如果某个数据库的模板文件不存在,跳过
continue
return templates
def reload_all_templates():
"""清空所有模板缓存"""
_load_template_file.cache_clear()
+2
View File
@@ -96,6 +96,8 @@ class Settings(BaseSettings):
EMBEDDING_TERMINOLOGY_TOP_COUNT: int = EMBEDDING_DEFAULT_TOP_COUNT
EMBEDDING_DATA_TRAINING_TOP_COUNT: int = EMBEDDING_DEFAULT_TOP_COUNT
GENERATE_SQL_QUERY_LIMIT_ENABLED: bool = True
PARSE_REASONING_BLOCK_ENABLED: bool = True
DEFAULT_REASONING_CONTENT_START: str = '<think>'
DEFAULT_REASONING_CONTENT_END: str = '</think>'
@@ -0,0 +1,86 @@
template:
quot_rule: |
<rule>
必须对数据库名、表名、字段名、别名外层加双引号(")。
<note>
1. 点号(.)不能包含在引号内,必须写成 "schema"."table"
2. 即使标识符不含特殊字符或非关键字,也需强制加双引号
3. Redshift 默认将未加引号的标识符转为小写
</note>
</rule>
limit_rule: |
<rule>
使用 LIMIT 或 FETCH FIRST 限制行数(Redshift 兼容 PostgreSQL)
<note>
1. 标准写法:LIMIT 100
2. 可选写法:FETCH FIRST 100 ROWS ONLY
</note>
</rule>
other_rule: |
<rule>必须为每个表生成别名(不加AS)</rule>
<rule>禁止使用星号(*),必须明确字段名</rule>
<rule>中文/特殊字符字段需保留原名并添加英文别名</rule>
<rule>函数字段必须加别名</rule>
<rule>百分比字段保留两位小数并以%结尾(使用ROUND+CONCAT)</rule>
<rule>避免与Redshift关键字冲突(如USER/GROUP/ORDER等)</rule>
basic_example: |
<basic-examples>
<intro>
📌 以下示例严格遵循<Rules>中的 AWS Redshift 规范,展示符合要求的 SQL 写法与典型错误案例。
⚠️ 注意:示例中的表名、字段名均为演示虚构,实际使用时需替换为用户提供的真实标识符。
🔍 重点观察:
1. 双引号包裹所有数据库对象的规范用法
2. 中英别名/百分比/函数等特殊字段的处理
3. 关键字冲突的规避方式
</intro>
<example>
<input>查询 TEST.SALES 表的前100条订单(含百分比计算)</input>
<output-bad>
SELECT * FROM TEST.SALES LIMIT 100 -- 错误:未加引号、使用星号
SELECT "订单ID", "金额" FROM "TEST"."SALES" "t1" FETCH FIRST 100 ROWS ONLY -- 错误:缺少英文别名
SELECT COUNT("订单ID") FROM "TEST"."SALES" "t1" -- 错误:函数未加别名
</output-bad>
<output-good>
SELECT
"t1"."订单ID" AS "order_id",
"t1"."金额" AS "amount",
COUNT("t1"."订单ID") AS "total_orders",
CONCAT(ROUND("t1"."折扣率" * 100, 2), '%') AS "discount_percent"
FROM "TEST"."SALES" "t1"
LIMIT 100
</output-good>
</example>
<example>
<input>统计用户表 PUBLIC.USERS(含关键字字段user)的活跃占比</input>
<output-bad>
SELECT user, status FROM PUBLIC.USERS -- 错误:未处理关键字和引号
SELECT "user", ROUND(active_ratio) FROM "PUBLIC"."USERS" -- 错误:百分比格式错误
</output-bad>
<output-good>
SELECT
"u"."user" AS "user_account",
CONCAT(ROUND("u"."active_ratio" * 100, 2), '%') AS "active_percent"
FROM "PUBLIC"."USERS" "u"
WHERE "u"."status" = 1
FETCH FIRST 1000 ROWS ONLY
</output-good>
</example>
</basic-examples>
example_engine: AWS Redshift 1.0
example_answer_1: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\"","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_1_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\" LIMIT 1000 OFFSET 0","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_2: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_2_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC LIMIT 1000 OFFSET 0","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_3: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国'","tables":["sample_country_gdp"],"chart-type":"table"}
example_answer_3_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国' LIMIT 1000 OFFSET 0","tables":["sample_country_gdp"],"chart-type":"table"}
@@ -0,0 +1,90 @@
template:
quot_rule: |
<rule>
必须对数据库名、表名、字段名、别名外层加双引号(")。
<note>
1. 点号(.)不能包含在引号内,必须写成 "database"."table"
2. ClickHouse 严格区分大小写,必须通过引号保留原始大小写
3. 嵌套字段使用点号连接:`"json_column.field"`
</note>
</rule>
limit_rule: |
<rule>
行数限制使用标准SQL语法:
<note>
1. 标准写法:LIMIT [count]
2. 分页写法:LIMIT [count] OFFSET [start]
3. 禁止使用原生 `topk()` 等函数替代
</note>
</rule>
other_rule: |
<rule>必须为每个表生成简短别名(如t1/t2)</rule>
<rule>禁止使用星号(*),必须明确字段名</rule>
<rule>JSON字段需用点号语法访问:`"column.field"`</rule>
<rule>函数字段必须加别名</rule>
<rule>百分比显示为:`ROUND(x*100,2) || '%'`</rule>
<rule>避免与ClickHouse关键字冲突(如`timestamp`/`default`)</rule>
basic_example: |
<basic-examples>
<intro>
📌 以下示例严格遵循<Rules>中的 ClickHouse 规范,展示符合要求的 SQL 写法与典型错误案例。
⚠️ 注意:示例中的表名、字段名均为演示虚构,实际使用时需替换为用户提供的真实标识符。
🔍 重点观察:
1. 双引号包裹所有数据库对象的规范用法
2. 中英别名/百分比/函数等特殊字段的处理
3. 关键字冲突的规避方式
</intro>
<example>
<input>查询 events 表的前100条错误日志(含JSON字段)</input>
<output-bad>
SELECT * FROM default.events LIMIT 100 -- 错误1:使用星号
SELECT message FROM "default"."events" WHERE level = 'error' -- 错误2:未处理JSON字段
SELECT "message", "extra.error_code" FROM events LIMIT 100 -- 错误3:表名未加引号
</output-bad>
<output-good>
SELECT
"e"."message" AS "log_content",
"e"."extra"."error_code" AS "error_id",
toDateTime("e"."timestamp") AS "log_time"
FROM "default"."events" "e"
WHERE "e"."level" = 'error'
LIMIT 100
</output-good>
</example>
<example>
<input>统计各地区的错误率Top 5(含百分比)</input>
<output-bad>
SELECT region, COUNT(*) FROM events GROUP BY region -- 错误1:使用COUNT(*)
SELECT "region", MAX("count") FROM "events" GROUP BY 1 -- 错误2:使用序号分组
</output-bad>
<output-good>
SELECT
"e"."region" AS "area",
COUNT(*) AS "total",
COUNTIf("e"."level" = 'error') AS "error_count",
ROUND(error_count * 100.0 / total, 2) || '%' AS "error_rate"
FROM "default"."events" "e"
GROUP BY "e"."region"
ORDER BY "error_rate" DESC
LIMIT 5
</output-good>
</example>
</basic-examples>
example_engine: ClickHouse 23.3
example_answer_1: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\"","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_1_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\" LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_2: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_2_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_3: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国'","tables":["sample_country_gdp"],"chart-type":"table"}
example_answer_3_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国' LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"table"}
+87
View File
@@ -0,0 +1,87 @@
template:
quot_rule: |
<rule>
必须对模式名、表名、字段名、别名外层加双引号(")。
<note>
1. 点号(.)不能包含在引号内,必须写成 "schema"."table"
2. 即使标识符不含特殊字符或非关键字,也需强制加双引号
3. 达梦默认将未加引号的标识符转为大写
</note>
</rule>
limit_rule: |
<rule>
行数限制使用达梦兼容语法:
<note>
1. 标准写法:LIMIT [count]
2. 分页写法:LIMIT [offset], [count] 或 LIMIT [count] OFFSET [start]
3. 兼容Oracle写法:WHERE ROWNUM <= 100(需达梦7+版本)
</note>
</rule>
other_rule: |
<rule>必须为每个表生成别名(不加AS)</rule>
<rule>禁止使用星号(*),必须明确字段名</rule>
<rule>中文/特殊字符字段需保留原名并添加英文别名</rule>
<rule>函数字段必须加别名</rule>
<rule>百分比字段使用TO_CHAR(x*100,'990.99') || '%'</rule>
<rule>避免与达梦关键字冲突(如LEVEL/ORDER/PARTITION等)</rule>
basic_example: |
<basic-examples>
<intro>
📌 以下示例严格遵循<Rules>中的 达梦(DM) 规范,展示符合要求的 SQL 写法与典型错误案例。
⚠️ 注意:示例中的表名、字段名均为演示虚构,实际使用时需替换为用户提供的真实标识符。
🔍 重点观察:
1. 双引号包裹所有数据库对象的规范用法
2. 中英别名/百分比/函数等特殊字段的处理
3. 关键字冲突的规避方式
</intro>
<example>
<input>查询 TEST.ORDERS 表的前100条订单(含中文字段和百分比)</input>
<output-bad>
SELECT * FROM TEST.ORDERS LIMIT 100 -- 错误:未加引号、使用星号
SELECT "订单ID", "金额" FROM "TEST"."ORDERS" "t1" WHERE ROWNUM <= 100 -- 错误:混用ROWNUM和LIMIT
SELECT COUNT("订单ID") FROM "TEST"."ORDERS" "t1" -- 错误:函数未加别名
</output-bad>
<output-good>
SELECT
"t1"."订单ID" AS "order_id",
"t1"."金额" AS "amount",
COUNT("t1"."订单ID") AS "total_orders",
TO_CHAR("t1"."折扣率" * 100, '990.99') || '%' AS "discount_percent"
FROM "TEST"."ORDERS" "t1"
LIMIT 100
</output-good>
</example>
<example>
<input>统计用户表 PUBLIC.USERS(含关键字字段LEVEL)的活跃占比</input>
<output-bad>
SELECT LEVEL, status FROM PUBLIC.USERS -- 错误:未处理关键字
SELECT "LEVEL", ROUND(active_ratio*100) FROM "PUBLIC"."USERS" -- 错误:百分比格式错误
</output-bad>
<output-good>
SELECT
"u"."LEVEL" AS "user_level",
TO_CHAR("u"."active_ratio" * 100, '990.99') || '%' AS "active_percent"
FROM "PUBLIC"."USERS" "u"
WHERE "u"."status" = 1
LIMIT 0, 1000 -- 达梦兼容写法
</output-good>
</example>
</basic-examples>
example_engine: DM Database 8
example_answer_1: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\"","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_1_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\" LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_2: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_2_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_3: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国'","tables":["sample_country_gdp"],"chart-type":"table"}
example_answer_3_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国' LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"table"}
+89
View File
@@ -0,0 +1,89 @@
template:
quot_rule: |
<rule>
必须对数据库名、表名、字段名、别名外层加反引号(`)。
<note>
1. 点号(.)不能包含在反引号内,必须写成 `database`.`table`
2. 当标识符为关键字、含特殊字符或需保留大小写时必须加反引号
3. Doris 标识符默认不区分大小写,但建议统一使用反引号
</note>
</rule>
limit_rule: |
<rule>
行数限制使用标准SQL语法:
<note>
1. 标准写法:LIMIT [count]
2. 分页写法:LIMIT [count] OFFSET [start]
3. 支持 MySQL 兼容写法:LIMIT [offset], [count]
</note>
</rule>
other_rule: |
<rule>必须为每个表生成别名(不加AS)</rule>
<rule>禁止使用星号(*),必须明确字段名</rule>
<rule>中文/特殊字符字段需保留原名并添加英文别名</rule>
<rule>函数字段必须加别名</rule>
<rule>百分比显示为:CONCAT(ROUND(x*100,2),'%')</rule>
<rule>避免与Doris关键字冲突(如`rank`/`partition`/`values`)</rule>
<rule>分区查询需使用PARTITION语句明确指定</rule>
basic_example: |
<basic-examples>
<intro>
📌 以下示例严格遵循<Rules>中的 Doris 规范,展示符合要求的 SQL 写法与典型错误案例。
⚠️ 注意:示例中的表名、字段名均为演示虚构,实际使用时需替换为用户提供的真实标识符。
🔍 重点观察:
1. 双引号包裹所有数据库对象的规范用法
2. 中英别名/百分比/函数等特殊字段的处理
3. 关键字冲突的规避方式
</intro>
<example>
<input>查询 test.orders 表的前100条订单(含中文字段和百分比)</input>
<output-bad>
SELECT * FROM test.orders LIMIT 100 -- 错误:使用星号
SELECT `订单ID`, `金额` FROM `test`.`orders` `t1` LIMIT 100 -- 错误:缺少英文别名
SELECT COUNT(`订单ID`) FROM `test`.`orders` `t1` -- 错误:函数未加别名
</output-bad>
<output-good>
SELECT
`t1`.`订单ID` AS `order_id`,
`t1`.`金额` AS `amount`,
COUNT(`t1`.`订单ID`) AS `total_orders`,
CONCAT(ROUND(`t1`.`折扣率` * 100, 2), '%') AS `discount_percent`
FROM `test`.`orders` `t1`
LIMIT 100
</output-good>
</example>
<example>
<input>统计用户表 dw.users(含分区字段和关键字rank)的活跃占比</input>
<output-bad>
SELECT rank, status FROM dw.users -- 错误:未处理关键字
SELECT `rank`, ROUND(active_ratio*100) FROM `dw`.`users` -- 错误:百分比格式错误
</output-bad>
<output-good>
SELECT
`u`.`rank` AS `user_rank`,
CONCAT(ROUND(`u`.`active_ratio` * 100, 2), '%') AS `active_percent`
FROM `dw`.`users` `u`
WHERE `u`.`status` = 1
AND `u`.`dt` = '2024-01-01' -- Doris分区字段过滤
LIMIT 1000
</output-good>
</example>
</basic-examples>
example_engine: Apache Doris 2.0
example_answer_1: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `continent` AS `continent_name`, `year` AS `year`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` ORDER BY `country`, `year`","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_1_with_limit: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `continent` AS `continent_name`, `year` AS `year`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` ORDER BY `country`, `year` LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_2: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` WHERE `year` = '2024' ORDER BY `gdp` DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_2_with_limit: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` WHERE `year` = '2024' ORDER BY `gdp` DESC LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_3: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` WHERE `year` = '2025' AND `country` = '中国'","tables":["sample_country_gdp"],"chart-type":"table"}
example_answer_3_with_limit: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` WHERE `year` = '2025' AND `country` = '中国' LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"table"}
@@ -0,0 +1,91 @@
template:
quot_rule: |
<rule>
必须对索引名(表名)、字段名、别名外层加双引号(")。
<note>
1. 通配符索引需整体加引号:`"logs-*"`
2. 嵌套字段用点号连接:`"user.name"`
3. 时间字段必须显式转换:`CAST("@timestamp" AS TIMESTAMP)`
</note>
</rule>
limit_rule: |
<rule>
行数限制必须使用标准SQL语法:
<note>
1. 首选:`LIMIT [count]`
2. 分页:`LIMIT [count] OFFSET [start]`
3. 禁止使用Elasticsearch原生`size/from`参数
</note>
</rule>
other_rule: |
<rule>必须为每个索引生成别名(不加AS)</rule>
<rule>禁止使用星号(*),必须明确字段名</rule>
<rule>中文/特殊字符字段需保留原名并添加英文别名</rule>
<rule>函数字段必须加别名</rule>
<rule>百分比显示为:`ROUND(x*100,2) || '%'`</rule>
<rule>避免与Elasticsearch关键字冲突(如`score`/`type`)</rule>
basic_example: |
<basic-examples>
<intro>
📌 以下示例严格遵循<Rules>中的 Elasticsearch 规范,展示符合要求的 SQL 写法与典型错误案例。
⚠️ 注意:示例中的表名、字段名均为演示虚构,实际使用时需替换为用户提供的真实标识符。
🔍 重点观察:
1. 双引号包裹所有数据库对象的规范用法
2. 中英别名/百分比/函数等特殊字段的处理
3. 关键字冲突的规避方式
</intro>
<example>
<input>查询 logs-* 索引的前100条错误日志(含时间过滤)</input>
<output-bad>
SELECT * FROM logs-* WHERE level = 'error' LIMIT 100 -- 错误1:使用星号
SELECT message FROM "logs-*" WHERE @timestamp > NOW() - 1d -- 错误2:未转换时间
SELECT "message", "@timestamp" FROM "logs-*" LIMIT 100 -- 错误3:未处理时间字段
</output-bad>
<output-good>
SELECT
"l"."message" AS "log_content",
"l"."host.ip" AS "client_ip",
CAST("l"."@timestamp" AS TIMESTAMP) AS "log_time"
FROM "logs-*" "l"
WHERE "l"."level" = 'error'
AND CAST("l"."@timestamp" AS TIMESTAMP) > DATE_SUB(NOW(), INTERVAL 1 DAY)
LIMIT 100
</output-good>
</example>
<example>
<input>统计各地区的错误日志占比(Top 5)</input>
<output-bad>
SELECT region, COUNT(*) FROM "logs-*" GROUP BY region -- 错误1:使用COUNT(*)
SELECT "region", MAX("count") FROM "logs-*" GROUP BY 1 -- 错误2:使用序号分组
</output-bad>
<output-good>
SELECT
"l"."region" AS "area",
COUNT("l"."message") AS "error_count",
ROUND(COUNT("l"."message") * 100.0 / SUM(COUNT("l"."message")) OVER (), 2) || '%' AS "error_percent"
FROM "logs-*" "l"
WHERE "l"."level" = 'error'
GROUP BY "l"."region"
ORDER BY "error_count" DESC
LIMIT 5
</output-good>
</example>
</basic-examples>
example_engine: Elasticsearch SQL 8.9
example_answer_1: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\"","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_1_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\" LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_2: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_2_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_3: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国'","tables":["sample_country_gdp"],"chart-type":"table"}
example_answer_3_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国' LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"table"}
@@ -0,0 +1,83 @@
template:
quot_rule: |
<rule>
必须对数据库名、表名、字段名、别名外层加双引号(")。
<note>
1. 点号(.)不能包含在引号内,必须写成 "schema"."table"
2. 即使标识符不含特殊字符或非关键字,也需强制加双引号
3. Kingbase 默认将未加引号的标识符转为小写
</note>
</rule>
limit_rule: |
<rule>
行数限制使用标准语法:
<note>
1. 标准写法:LIMIT [count]
2. 分页写法:LIMIT [count] OFFSET [start]
3. 兼容 Oracle 写法:WHERE ROWNUM <= 100(需开启兼容模式)
</note>
</rule>
other_rule: |
<rule>必须为每个表生成别名(不加AS)</rule>
<rule>禁止使用星号(*),必须明确字段名</rule>
<rule>中文/特殊字符字段需保留原名并添加英文别名</rule>
<rule>函数字段必须加别名</rule>
<rule>百分比显示为:TO_CHAR(x*100,'990.99') || '%'</rule>
<rule>避免与Kingbase关键字冲突(如SYSDATE/LEVEL等)</rule>
basic_example: |
<basic-examples>
<intro>
📌 以下示例严格遵循 Kingbase 语法规范(兼容 PostgreSQL)
⚠️ 注意:示例中的表名、字段名均为演示虚构,实际使用时需替换为用户提供的真实标识符。
🔍 重点观察:
1. 双引号包裹所有数据库对象
2. 中英别名/百分比/函数等特殊字段处理
3. 关键字冲突规避(如SYSDATE/LEVEL)
</intro>
<example>
<input>查询 TEST.ORDERS 表的前100条订单(含中文字段)</input>
<output-bad>
SELECT * FROM TEST.ORDERS LIMIT 100 -- 错误:未加引号、使用星号
SELECT "订单ID", "金额" FROM "TEST"."ORDERS" "t1" -- 错误:缺少英文别名
</output-bad>
<output-good>
SELECT
"t1"."订单ID" AS "order_id",
"t1"."金额" AS "amount_usd",
TO_CHAR("t1"."折扣率" * 100, '990.99') || '%' AS "discount_percent"
FROM "TEST"."ORDERS" "t1"
LIMIT 100
</output-good>
</example>
<example>
<input>统计用户表 PUBLIC.USERS(含关键字字段LEVEL)</input>
<output-bad>
SELECT LEVEL, status FROM PUBLIC.USERS -- 错误:未处理关键字
SELECT "LEVEL", "active_ratio" FROM "PUBLIC"."USERS" -- 错误:百分比未格式化
</output-bad>
<output-good>
SELECT
"u"."LEVEL" AS "user_level",
TO_CHAR("u"."active_ratio" * 100, '990.99') || '%' AS "active_percent"
FROM "PUBLIC"."USERS" "u"
WHERE "u"."status" = 1
</output-good>
</example>
</basic-examples>
example_engine: Kingbase V8
example_answer_1: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\"","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_1_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\" LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_2: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_2_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_3: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国'","tables":["sample_country_gdp"],"chart-type":"table"}
example_answer_3_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp_usd\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国' LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"table"}
@@ -0,0 +1,87 @@
template:
quot_rule: |
<rule>
必须对数据库名、表名、字段名、别名外层加方括号([])。
<note>
1. 点号(.)不能包含在方括号内,必须写成 [schema].[table]
2. 当标识符为关键字、含特殊字符或需保留大小写时必须加方括号
3. SQL Server 标识符默认不区分大小写
</note>
</rule>
limit_rule: |
<rule>
行数限制使用标准SQL语法:
<note>
1. 标准写法:TOP [count]
2. 分页写法:OFFSET [start] ROWS FETCH NEXT [count] ROWS ONLY
3. 禁止使用 MySQL 的 LIMIT 语法
</note>
</rule>
other_rule: |
<rule>必须为每个表生成别名(不加AS)</rule>
<rule>禁止使用星号(*),必须明确字段名</rule>
<rule>中文/特殊字符字段需保留原名并添加英文别名</rule>
<rule>函数字段必须加别名</rule>
<rule>百分比显示为:CONVERT(VARCHAR, ROUND(x*100,2)) + '%'</rule>
<rule>避免与SQL Server关键字冲突(如[user]/[order]/[desc])</rule>
basic_example: |
<basic-examples>
<intro>
📌 以下示例严格遵循<Rules>中的 Microsoft SQL Server 规范,展示符合要求的 SQL 写法与典型错误案例。
⚠️ 注意:示例中的表名、字段名均为演示虚构,实际使用时需替换为用户提供的真实标识符。
🔍 重点观察:
1. 双引号包裹所有数据库对象的规范用法
2. 中英别名/百分比/函数等特殊字段的处理
3. 关键字冲突的规避方式
</intro>
<example>
<input>查询 Sales.Orders 表的前100条订单(含中文字段和百分比)</input>
<output-bad>
SELECT * FROM Sales.Orders -- 错误:使用星号
SELECT [订单ID], [金额] FROM [Sales].[Orders] [o] -- 错误:缺少英文别名
SELECT COUNT([订单ID]) FROM [Sales].[Orders] [o] -- 错误:函数未加别名
</output-bad>
<output-good>
SELECT TOP 100
[o].[订单ID] AS [order_id],
[o].[金额] AS [amount],
COUNT([o].[订单ID]) AS [total_orders],
CONVERT(VARCHAR, ROUND([o].[折扣率] * 100, 2)) + '%' AS [discount_percent]
FROM [Sales].[Orders] [o]
</output-good>
</example>
<example>
<input>统计用户表 dbo.Users(含关键字字段user)的活跃占比</input>
<output-bad>
SELECT user, status FROM dbo.Users -- 错误:未处理关键字
SELECT [user], ROUND(active_ratio*100) FROM [dbo].[Users] -- 错误:百分比格式错误
</output-bad>
<output-good>
SELECT
[u].[user] AS [user_name],
CONVERT(VARCHAR, ROUND([u].[active_ratio] * 100, 2)) + '%' AS [active_percent]
FROM [dbo].[Users] [u]
WHERE [u].[status] = 1
ORDER BY [u].[create_date]
OFFSET 0 ROWS FETCH NEXT 1000 ROWS ONLY
</output-good>
</example>
</basic-examples>
example_engine: Microsoft SQL Server 2022
example_answer_1: |
{"success":true,"sql":"SELECT [country] AS [country_name], [continent] AS [continent_name], [year] AS [year], [gdp] AS [gdp_usd] FROM [Sample_Database].[sample_country_gdp] ORDER BY [country], [year]","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_1_with_limit: |
{"success":true,"sql":"SELECT TOP 1000 [country] AS [country_name], [continent] AS [continent_name], [year] AS [year], [gdp] AS [gdp_usd] FROM [Sample_Database].[sample_country_gdp] ORDER BY [country], [year]","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_2: |
{"success":true,"sql":"SELECT [country] AS [country_name], [gdp] AS [gdp_usd] FROM [Sample_Database].[sample_country_gdp] WHERE [year] = '2024' ORDER BY [gdp] DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_2_with_limit: |
{"success":true,"sql":"SELECT TOP 1000 [country] AS [country_name], [gdp] AS [gdp_usd] FROM [Sample_Database].[sample_country_gdp] WHERE [year] = '2024' ORDER BY [gdp] DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_3: |
{"success":true,"sql":"SELECT [country] AS [country_name], [gdp] AS [gdp_usd] FROM [Sample_Database].[sample_country_gdp] WHERE [year] = '2025' AND [country] = N'中国'","tables":["sample_country_gdp"],"chart-type":"table"}
example_answer_3_with_limit: |
{"success":true,"sql":"SELECT TOP 1000 [country] AS [country_name], [gdp] AS [gdp_usd] FROM [Sample_Database].[sample_country_gdp] WHERE [year] = '2025' AND [country] = N'中国'","tables":["sample_country_gdp"],"chart-type":"table"}
+86
View File
@@ -0,0 +1,86 @@
template:
quot_rule: |
<rule>
必须对数据库名、表名、字段名、别名外层加反引号(`)。
<note>
1. 点号(.)不能包含在反引号内,必须写成 `schema`.`table`
2. 当标识符为关键字、含特殊字符或需保留大小写时必须加反引号
3. MySQL 默认不区分大小写(Linux系统区分表名大小写)
</note>
</rule>
limit_rule: |
<rule>
行数限制使用标准SQL语法:
<note>
1. 标准写法:LIMIT [count]
2. 分页写法:LIMIT [offset], [count] 或 LIMIT [count] OFFSET [start]
</note>
</rule>
other_rule: |
<rule>必须为每个表生成别名(不加AS)</rule>
<rule>禁止使用星号(*),必须明确字段名</rule>
<rule>中文/特殊字符字段需保留原名并添加英文别名</rule>
<rule>函数字段必须加别名</rule>
<rule>百分比显示为:CONCAT(ROUND(x*100,2),'%')</rule>
<rule>避免与MySQL关键字冲突(如`order`/`group`/`desc`)</rule>
basic_example: |
<basic-examples>
<intro>
📌 以下示例严格遵循<Rules>中的 MySQL 规范,展示符合要求的 SQL 写法与典型错误案例。
⚠️ 注意:示例中的表名、字段名均为演示虚构,实际使用时需替换为用户提供的真实标识符。
🔍 重点观察:
1. 双引号包裹所有数据库对象的规范用法
2. 中英别名/百分比/函数等特殊字段的处理
3. 关键字冲突的规避方式
</intro>
<example>
<input>查询 test.orders 表的前100条订单(含中文字段和百分比)</input>
<output-bad>
SELECT * FROM test.orders LIMIT 100 -- 错误:使用星号
SELECT `订单ID`, `金额` FROM `test`.`orders` `t1` LIMIT 100 -- 错误:缺少英文别名
SELECT COUNT(`订单ID`) FROM `test`.`orders` `t1` -- 错误:函数未加别名
</output-bad>
<output-good>
SELECT
`t1`.`订单ID` AS `order_id`,
`t1`.`金额` AS `amount`,
COUNT(`t1`.`订单ID`) AS `total_orders`,
CONCAT(ROUND(`t1`.`折扣率` * 100, 2), '%') AS `discount_percent`
FROM `test`.`orders` `t1`
LIMIT 100
</output-good>
</example>
<example>
<input>统计用户表 public.users(含关键字字段desc)的活跃占比</input>
<output-bad>
SELECT desc, status FROM public.users -- 错误:未处理关键字
SELECT `desc`, ROUND(active_ratio*100) FROM `public`.`users` -- 错误:百分比格式错误
</output-bad>
<output-good>
SELECT
`u`.`desc` AS `description`,
CONCAT(ROUND(`u`.`active_ratio` * 100, 2), '%') AS `active_percent`
FROM `public`.`users` `u`
WHERE `u`.`status` = 1
LIMIT 1000
</output-good>
</example>
</basic-examples>
example_engine: MySQL 8.0
example_answer_1: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `continent` AS `continent_name`, `year` AS `year`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` ORDER BY `country`, `year`","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_1_with_limit: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `continent` AS `continent_name`, `year` AS `year`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` ORDER BY `country`, `year` LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_2: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` WHERE `year` = '2024' ORDER BY `gdp` DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_2_with_limit: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` WHERE `year` = '2024' ORDER BY `gdp` DESC LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_3: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` WHERE `year` = '2025' AND `country` = '中国'","tables":["sample_country_gdp"],"chart-type":"table"}
example_answer_3_with_limit: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` WHERE `year` = '2025' AND `country` = '中国' LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"table"}
@@ -0,0 +1,86 @@
template:
quot_rule: |
<rule>
必须对数据库名、表名、字段名、别名外层加双引号(")。
<note>
1. 点号(.)不能包含在引号内,必须写成 "schema"."table"
2. 即使标识符不含特殊字符或非关键字,也需强制加双引号
3. Oracle 对象名默认大写,如需小写必须加双引号
</note>
</rule>
limit_rule: |
<rule>
使用 ROWNUM 或 FETCH FIRST 限制行数(Oracle 12c+)
<note>
1. 传统写法:WHERE ROWNUM <= 100
2. 现代写法:FETCH FIRST 100 ROWS ONLY
</note>
</rule>
other_rule: |
<rule>必须为每个表生成别名(不加AS)</rule>
<rule>禁止使用星号(*),必须明确字段名</rule>
<rule>中文/特殊字符字段需保留原名并添加英文别名</rule>
<rule>函数字段必须加别名</rule>
<rule>百分比字段保留两位小数并以%结尾</rule>
<rule>避免与 Oracle 关键字冲突(如 DATE/LEVEL/ORDER 等)</rule>
basic_example: |
<basic-examples>
<intro>
📌 以下示例严格遵循<Rules>中的 Oracle 规范,展示符合要求的 SQL 写法与典型错误案例。
⚠️ 注意:示例中的表名、字段名均为演示虚构,实际使用时需替换为用户提供的真实标识符。
🔍 重点观察:
1. 双引号包裹所有数据库对象的规范用法
2. 中英别名/百分比/函数等特殊字段的处理
3. 关键字冲突的规避方式
</intro>
<example>
<input>查询 TEST.ORDERS 表的前100条订单(含中文字段和百分比)</input>
<output-bad>
SELECT * FROM TEST.ORDERS WHERE ROWNUM <= 100 -- 错误:未加引号、使用星号
SELECT "订单ID", "金额" FROM "TEST"."ORDERS" "t1" WHERE ROWNUM <= 100 -- 错误:缺少英文别名
SELECT COUNT("订单ID") FROM "TEST"."ORDERS" "t1" -- 错误:函数未加别名
</output-bad>
<output-good>
SELECT
"t1"."订单ID" AS "order_id",
"t1"."金额" AS "amount",
COUNT("t1"."订单ID") AS "total_orders",
TO_CHAR("t1"."折扣率" * 100, '990.99') || '%' AS "discount_percent"
FROM "TEST"."ORDERS" "t1"
WHERE ROWNUM <= 100
</output-good>
</example>
<example>
<input>统计用户表 PUBLIC.USERS(含关键字字段DATE)的活跃占比</input>
<output-bad>
SELECT DATE, status FROM PUBLIC.USERS -- 错误:未处理关键字和引号
SELECT "DATE", ROUND(active_ratio) FROM "PUBLIC"."USERS" -- 错误:百分比格式错误
</output-bad>
<output-good>
SELECT
"u"."DATE" AS "create_date",
TO_CHAR("u"."active_ratio" * 100, '990.99') || '%' AS "active_percent"
FROM "PUBLIC"."USERS" "u"
WHERE "u"."status" = 1
AND ROWNUM <= 1000
</output-good>
</example>
</basic-examples>
example_engine: Oracle 19c
example_answer_1: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\"","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_1_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE ROWNUM <= 1000 ORDER BY \"country\", \"year\"","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_2: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_2_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' AND ROWNUM <= 1000 ORDER BY \"gdp\" DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_3: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国'","tables":["sample_country_gdp"],"chart-type":"table"}
example_answer_3_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国' AND ROWNUM <= 1000","tables":["sample_country_gdp"],"chart-type":"table"}
@@ -0,0 +1,80 @@
template:
quot_rule: |
<rule>
必须对数据库名、表名、字段名、别名外层加双引号(")。
<note>
1. 点号(.)不能包含在引号内,必须写成 "schema"."table"
2. 即使标识符不含特殊字符或非关键字,也需强制加双引号
</note>
</rule>
limit_rule: |
<rule>
使用 LIMIT 来限制行数
</rule>
other_rule: |
<rule>必须为每个表生成别名(不加AS)</rule>
<rule>禁止使用星号(*),必须明确字段名</rule>
<rule>中文/特殊字符字段需保留原名并添加英文别名</rule>
<rule>函数字段必须加别名</rule>
<rule>百分比字段保留两位小数并以%结尾</rule>
<rule>避免与数据库关键字冲突</rule>
basic_example: |
<basic-examples>
<intro>
📌 以下示例严格遵循<Rules>中的 PostgreSQL 规范,展示符合要求的 SQL 写法与典型错误案例。
⚠️ 注意:示例中的表名、字段名均为演示虚构,实际使用时需替换为用户提供的真实标识符。
🔍 重点观察:
1. 双引号包裹所有数据库对象的规范用法
2. 中英别名/百分比/函数等特殊字段的处理
3. 关键字冲突的规避方式
</intro>
<example>
<input>查询 TEST.ORDERS 表的前100条订单(含中文字段和百分比)</input>
<output-bad>
SELECT * FROM TEST.ORDERS LIMIT 100 -- 错误:未加引号、使用星号
SELECT "订单ID", "金额" FROM "TEST"."ORDERS" "t1" LIMIT 100 -- 错误:缺少英文别名
SELECT COUNT("订单ID") FROM "TEST"."ORDERS" "t1" -- 错误:函数未加别名
</output-bad>
<output-good>
SELECT
"t1"."订单ID" AS "order_id",
"t1"."金额" AS "amount",
COUNT("t1"."订单ID") AS "total_orders",
ROUND("t1"."折扣率" * 100, 2) || '%' AS "discount_percent"
FROM "TEST"."ORDERS" "t1"
LIMIT 100
</output-good>
</example>
<example>
<input>统计用户表 PUBLIC.USERS(含关键字字段user)的活跃占比</input>
<output-bad>
SELECT user, status FROM PUBLIC.USERS -- 错误:未处理关键字和引号
SELECT "user", ROUND(active_ratio) FROM "PUBLIC"."USERS" -- 错误:百分比格式错误
</output-bad>
<output-good>
SELECT
"u"."user" AS "username",
ROUND("u"."active_ratio" * 100, 2) || '%' AS "active_percent"
FROM "PUBLIC"."USERS" "u"
WHERE "u"."status" = 1
</output-good>
</example>
</basic-examples>
example_engine: PostgreSQL17.6 (Debian 17.6-1.pgdg12+1)
example_answer_1: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\"","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_1_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\" LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_2: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_2_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_3: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国'","tables":["sample_country_gdp"],"chart-type":"table"}
example_answer_3_with_limit: |
{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国' LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"table"}
@@ -0,0 +1,88 @@
template:
quot_rule: |
<rule>
必须对数据库名、表名、字段名、别名外层加反引号(`)。
<note>
1. 点号(.)不能包含在反引号内,必须写成 `database`.`table`
2. 当标识符为关键字、含特殊字符或需保留大小写时必须加反引号
3. StarRocks 标识符默认不区分大小写,但建议统一使用反引号
</note>
</rule>
limit_rule: |
<rule>
行数限制使用标准SQL语法:
<note>
1. 标准写法:LIMIT [count]
2. 分页写法:LIMIT [count] OFFSET [start]
3. 支持 MySQL 兼容写法:LIMIT [offset], [count]
</note>
</rule>
other_rule: |
<rule>必须为每个表生成别名(不加AS)</rule>
<rule>禁止使用星号(*),必须明确字段名</rule>
<rule>中文/特殊字符字段需保留原名并添加英文别名</rule>
<rule>函数字段必须加别名</rule>
<rule>百分比显示为:CONCAT(ROUND(x*100,2),'%')</rule>
<rule>避免与StarRocks关键字冲突(如`rank`/`partition`/`values`)</rule>
<rule>分区查询需使用PARTITION语句明确指定</rule>
<rule>优先使用Colocate Group特性优化JOIN性能</rule>
basic_example: |
<basic-examples>
<intro>
📌 以下示例严格遵循 StarRocks 规范(兼容 MySQL 协议)
⚠️ 注意:示例中的表名、字段名均为演示虚构,实际使用时需替换为用户提供的真实标识符。
🔍 重点观察:
1. 反引号包裹所有数据库对象
2. 分区/分桶等MPP优化特性
3. 关键字冲突规避(如`rank`)
</intro>
<example>
<input>查询 test.orders 表的前100条订单(含中文字段)</input>
<output-bad>
SELECT * FROM test.orders LIMIT 100 -- 错误:使用星号
SELECT `订单ID`, `金额` FROM `test`.`orders` `t1` -- 错误:缺少英文别名
</output-bad>
<output-good>
SELECT
`t1`.`订单ID` AS `order_id`,
`t1`.`金额` AS `amount_usd`,
CONCAT(ROUND(`t1`.`折扣率` * 100, 2), '%') AS `discount_percent`
FROM `test`.`orders` `t1`
PARTITION (`p2023`) -- StarRocks分区裁剪
LIMIT 100
</output-good>
</example>
<example>
<input>统计用户表 dw.users(含关键字rank)的活跃占比</input>
<output-bad>
SELECT rank, status FROM dw.users -- 错误:未处理关键字
SELECT `rank`, active_ratio FROM `dw`.`users` -- 错误:百分比未格式化
</output-bad>
<output-good>
SELECT
`u`.`rank` AS `user_rank`,
CONCAT(ROUND(`u`.`active_ratio` * 100, 2), '%') AS `active_percent`
FROM `dw`.`users` `u`
WHERE `u`.`status` = 1
AND `u`.`dt` = '2024-01-01' -- 分区键过滤
LIMIT 1000
</output-good>
</example>
</basic-examples>
example_engine: StarRocks 3.0
example_answer_1: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `continent` AS `continent_name`, `year` AS `year`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` ORDER BY `country`, `year`","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_1_with_limit: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `continent` AS `continent_name`, `year` AS `year`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` ORDER BY `country`, `year` LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"line"}
example_answer_2: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` WHERE `year` = '2024' ORDER BY `gdp` DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_2_with_limit: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` WHERE `year` = '2024' ORDER BY `gdp` DESC LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"pie"}
example_answer_3: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` WHERE `year` = '2025' AND `country` = '中国'","tables":["sample_country_gdp"],"chart-type":"table"}
example_answer_3_with_limit: |
{"success":true,"sql":"SELECT `country` AS `country_name`, `gdp` AS `gdp_usd` FROM `Sample_Database`.`sample_country_gdp` WHERE `year` = '2025' AND `country` = '中国' LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"table"}
@@ -6,6 +6,11 @@ template:
{data_training}
sql:
query_limit: |
<rule>
如果用户没有指定数据条数的限制,输出的查询SQL必须加上1000条的数据条数限制。
如果用户指定的限制大于1000,则按1000处理。
</rule>
system: |
<Instruction>
你是"SQLBOT",智能问数小助手,可以根据用户提问,专业生成SQL与可视化图表。
@@ -55,43 +60,8 @@ template:
<rule>
提问中如果有涉及数据源名称或数据源描述的内容,则忽略数据源的信息,直接根据剩余内容生成SQL
</rule>
<rule>
根据表结构生成SQL语句,需给每个表名生成一个别名(不要加AS)
</rule>
<rule>
SQL查询中不能使用星号(*),必须明确指定字段名
</rule>
<rule>
SQL查询的字段名不要自动翻译,别名必须为英文
</rule>
<rule>
SQL查询的字段若是函数字段,如 COUNT(),CAST() 等,必须加上别名
</rule>
<rule>
计算占比,百分比类型字段,保留两位小数,以%结尾
</rule>
<rule>
生成SQL时,必须避免与数据库关键字冲突
</rule>
<rule>
如数据库引擎是 PostgreSQL、Oracle、ClickHouse、达梦(DM)、AWS Redshift、Elasticsearch,则在schema、表名、字段名、别名外层加双引号;
如数据库引擎是 MySQL、Doris,则在表名、字段名、别名外层加反引号;
如数据库引擎是 Microsoft SQL Server,则在schema、表名、字段名、别名外层加方括号。
<example>
以 PostgreSQL 为例,查询Schema为TEST表TABLE下前1000条id字段,则生成的SQL为:
SELECT "id" FROM "TEST"."TABLE" LIMIT 1000
- 注意在表名外双引号的位置,千万不要生成为:
SELECT "id" FROM "TEST.TABLE" LIMIT 1000
以 Microsoft SQL Server 为例,查询Schema为TEST表TABLE下前1000条id字段,则生成的SQL为:
SELECT TOP 1000 [id] FROM [TEST].[TABLE]
- 注意在表名外方括号的位置,千万不要生成为:
SELECT TOP 1000 [id] FROM [TEST.TABLE]
以 MySQL 为例,查询Schema为TEST表TABLE下前1000条id字段,则生成的SQL为:
SELECT `id` FROM `TEST`.`TABLE` LIMIT 1000
- 注意在表名外反引号的位置,千万不要生成为:
SELECT `id` FROM `TEST.TABLE` LIMIT 1000
</example>
</rule>
{base_sql_rules}
{query_limit}
<rule>
如果生成SQL的字段内有时间格式的字段:
- 若提问中没有指定查询顺序,则默认按时间升序排序
@@ -105,26 +75,6 @@ template:
生成的SQL查询结果可以用来进行图表展示,需要注意排序字段的排序优先级,例如:
- 柱状图或折线图:适合展示在横轴的字段优先排序,若SQL包含分类字段,则分类字段次一级排序
</rule>
<rule>
如果用户没有指定数据条数的限制,输出的查询SQL必须加上1000条的数据条数限制
如果用户指定的限制大于1000,则按1000处理
<rule-example>
以 PostgreSQL 为例,查询Schema为TEST表TABLE下id字段,则生成的SQL为:
SELECT "id" FROM "TEST"."TABLE" LIMIT 1000
以 Microsoft SQL Server 为例,查询Schema为TEST表TABLE下id字段,则生成的SQL为:
- 使用 TOP(适用于所有 SQL Server 版本,需要注意 TOP 在SQL中的位置):
SELECT TOP 1000 [id] FROM [TEST].[TABLE]
- 使用 OFFSET-FETCH(SQL Server 2012+):
SELECT "id" FROM "TEST"."TABLE"
ORDER BY "id" -- 必须指定 ORDER BY
OFFSET 0 ROWS FETCH NEXT 1000 ROWS ONLY
以 Oracle 为例,查询Schema为TEST表TABLE下id字段,则生成的SQL为:
- 使用ROWNUM(适用于所有Oracle版本):
SELECT "id" FROM "TEST"."TABLE" WHERE ROWNUM <= 1000
- 使用FETCH FIRST(Oracle 12c及以上版本):
SELECT "id" FROM "TEST"."TABLE" FETCH FIRST 1000 ROWS ONLY
</rule-example>
</rule>
<rule>
若需关联多表,优先使用<m-schema>中标记为"Primary key"/"ID"/"主键"的字段作为关联条件。
</rule>
@@ -133,11 +83,19 @@ template:
</rule>
</Rules>
以下<example>帮助你理解问题及返回格式的例子,不要将<example>内的表结构用来回答用户的问题,<example>内的<input>为后续用户提问传入的内容,<output>为根据模版与输入的输出回答
以下<example>内的例子的SQL语法只是针对该例子的<db-engine>内PostgreSQL的对应数据库语法,你生成的SQL语法必须按照当前对话实际给出的<db-engine>来生成
{basic_sql_examples}
<example>
<intro>
📌 以下示例仅用于演示问题理解与回答格式,不包含实际表结构
⚠️ 注意:示例中的SQL语法仅适用于对应<db-engine>标注的数据库类型
🔍 重点观察:
1. <input>代表用户可能的提问输入内容
2. <output>展示根据模板规则生成的响应
3. 实际生成时必须使用当前对话指定的数据库语法
</intro>
<Info>
<db-engine> PostgreSQL17.6 (Debian 17.6-1.pgdg12+1) </db-engine>
<db-engine> {example_engine} </db-engine>
<m-schema>
【DB_ID】 Sample_Database, 样例数据库
【Schema】
@@ -203,7 +161,7 @@ template:
<user-question>查询各个国家每年的GDP</user-question>
</input>
<output>
{{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"continent\" AS \"continent_name\", \"year\" AS \"year\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" ORDER BY \"country\", \"year\" LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"line"}}
{example_answer_1}
</output>
</example>
<example>
@@ -215,7 +173,7 @@ template:
</background-infos>
<user-question>使用饼图展示去年各个国家的GDP</user-question>
</input>
{{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"pie"}}
{example_answer_2}
<output>
</output>
</example>
@@ -228,7 +186,7 @@ template:
</background-infos>
<user-question>查询今年中国大陆的GDP</user-question>
</input>
{{"success":true,"sql":"SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2025' AND \"country\" = '中国' LIMIT 1000","tables":["sample_country_gdp"],"chart-type":"table"}}
{example_answer_3}
<output>
</output>
</example>