diff --git a/backend/apps/chat/models/chat_model.py b/backend/apps/chat/models/chat_model.py
index 5e7f0136..7713270f 100644
--- a/backend/apps/chat/models/chat_model.py
+++ b/backend/apps/chat/models/chat_model.py
@@ -185,8 +185,12 @@ class AiModelQuestion(BaseModel):
def sql_sys_question(self, db_type: Union[str, DB], enable_query_limit: bool = True):
_sql_template = get_sql_example_template(db_type)
- _query_limit = get_sql_template()['query_limit'] if enable_query_limit else get_sql_template()['no_query_limit']
- _base_sql_rules = _sql_template['quot_rule'] + _query_limit + _sql_template['limit_rule'] + _sql_template['other_rule']
+ _base_template = get_sql_template()
+ _process_check = _sql_template.get('process_check') if _sql_template.get('process_check') else _base_template[
+ 'process_check']
+ _query_limit = _base_template['query_limit'] if enable_query_limit else _base_template['no_query_limit']
+ _base_sql_rules = _sql_template['quot_rule'] + _query_limit + _sql_template['limit_rule'] + _sql_template[
+ 'other_rule']
_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[
@@ -195,15 +199,16 @@ def sql_sys_question(self, db_type: Union[str, DB], enable_query_limit: bool = T
'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,
- base_sql_rules=_base_sql_rules,
- 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)
+ return _base_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,
+ process_check=_process_check,
+ base_sql_rules=_base_sql_rules,
+ 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,
diff --git a/backend/templates/sql_examples/Oracle.yaml b/backend/templates/sql_examples/Oracle.yaml
index b7293465..ba3015b2 100644
--- a/backend/templates/sql_examples/Oracle.yaml
+++ b/backend/templates/sql_examples/Oracle.yaml
@@ -1,4 +1,18 @@
template:
+ process_check: |
+
+ 1. 分析用户问题,确定查询需求
+ 2. 根据表结构生成基础SQL
+ 3. 强制检查:SQL是否包含GROUP BY/聚合函数?
+ 4. 如果是GROUP BY查询:必须使用外层查询结构包裹
+ 5. 强制检查:应用数据量限制规则
+ 6. 应用其他规则(引号、别名等)
+ 7. 最终验证:GROUP BY查询的ROWNUM位置是否正确?
+ 8. 强制检查:检查语法是否正确?
+ 9. 确定图表类型
+ 10. 返回JSON结果
+
+
quot_rule: |
必须对数据库名、表名、字段名、别名外层加双引号(")。
@@ -10,42 +24,61 @@ template:
limit_rule: |
-
- 当需要限制行数时:
- 1. 12c以下版本必须使用ROWNUM语法
- 2. 12c+版本推荐使用FETCH FIRST语法
-
- 版本适配:
- - Oracle 12c以下:必须使用 WHERE ROWNUM <= N
- - Oracle 12c+:推荐使用 FETCH FIRST N ROWS ONLY
-
-
- 重要:ROWNUM必须放在正确的位置,避免语法错误
- 1. 单层查询:ROWNUM直接跟在WHERE子句后
- SELECT ... FROM table WHERE conditions AND ROWNUM <= N
- 2. 多层查询:ROWNUM只能放在最外层
-
- SELECT ... FROM (
- SELECT ... FROM table WHERE conditions GROUP BY ...
- ) WHERE ROWNUM <= N -- 正确:在最外层
-
- 3. 禁止的错误写法:
-
- SELECT ... FROM table
- WHERE conditions
- GROUP BY ...
- ORDER BY ...
- WHERE ROWNUM <= N -- 错误:不能有多个WHERE
-
- 4. 正确顺序:WHERE → GROUP BY → HAVING → ORDER BY → ROWNUM
- 5. 括号位置:从内层SELECT开始到内层结束都要括起来
-
- SELECT ... FROM (
- -- 内层完整查询(包含自己的SELECT、FROM、WHERE、GROUP BY、ORDER BY)
- SELECT columns FROM table WHERE conditions GROUP BY ... ORDER BY ...
- ) alias WHERE ROWNUM <= N
-
-
+
+ Oracle版本语法适配
+
+ 如果db-engine版本号小于12
+ 必须使用ROWNUM语法
+ 如果db-engine版本号大于等于12
+ 推荐使用FETCH FIRST语法
+
+
+
+ Oracle数据库 FETCH FIRST 语法规范
+ 若使用 FETCH FIRST 语法,则必须遵循该规范
+
+ SELECT ... FROM table WHERE conditions FETCH FIRST N ROWS ONLY
+
+
+
+ Oracle数据库ROWNUM语法规范
+ 若使用ROWNUM语法,则必须遵循该规范
+
+
+ 简单查询
+ SELECT ... FROM table WHERE conditions AND ROWNUM <= N
+
+
+ 语法禁区
+
+ - 禁止多个WHERE子句
+ - 禁止ROWNUM在GROUP BY内层(影响分组结果)
+ - 禁止括号不完整
+
+
+
+
+
+ GROUP BY查询的ROWNUM强制规范(必须严格遵守)
+ 所有包含GROUP BY或聚合函数的查询必须使用外层查询结构
+ ROWNUM必须放在最外层查询的WHERE子句中
+
+
+ 如果SQL包含GROUP BY、COUNT、SUM等聚合函数
+ 必须使用:SELECT ... FROM (内层完整查询) WHERE ROWNUM <= N
+ 否则(简单查询)
+ 可以使用:SELECT ... FROM table WHERE conditions AND ROWNUM <= N
+
+
+
+ -- 错误:ROWNUM在内层影响分组结果
+ SELECT ... GROUP BY ... WHERE ROWNUM <= N
+
+
+
+ -- 正确:ROWNUM在外层
+ SELECT ... FROM (SELECT ... GROUP BY ...) WHERE ROWNUM <= N
+
other_rule: |
@@ -73,7 +106,7 @@ template:
SELECT "订单ID", "金额" FROM "TEST"."ORDERS" "t1" WHERE ROWNUM <= 100 -- 错误:缺少英文别名
SELECT COUNT("订单ID") FROM "TEST"."ORDERS" "t1" -- 错误:函数未加别名
-
+
SELECT
"t1"."订单ID" AS "order_id",
"t1"."金额" AS "amount",
@@ -90,7 +123,7 @@ template:
SELECT DATE, status FROM PUBLIC.USERS -- 错误:未处理关键字和引号
SELECT "DATE", ROUND(active_ratio) FROM "PUBLIC"."USERS" -- 错误:百分比格式错误
-
+
SELECT
"u"."DATE" AS "create_date",
TO_CHAR("u"."active_ratio" * 100, '990.99') || '%' AS "active_percent"
@@ -98,6 +131,14 @@ template:
WHERE "u"."status" = 1
AND ROWNUM <= 1000
+
+ 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
+ FETCH FIRST 1000 ROWS ONLY
+
@@ -108,9 +149,9 @@ template:
count(*) AS "user_count"
FROM "PUBLIC"."USERS" "u"
WHERE "u"."status" = 1
- AND ROWNUM <= 100
+ AND ROWNUM <= 100 -- 严重错误:影响分组结果!
GROUP BY "u"."DEPARTMENT"
- ORDER BY "department_name" -- 错误:ROWNUM 应当写在最外层,这样会导致查询结果条数比实际数据的数量少
+ ORDER BY "department_name"
SELECT "department_name", "user_count" FROM
@@ -123,7 +164,7 @@ template:
ORDER BY "department_name"
WHERE ROWNUM <= 100 -- 错误:语法错误,同级内只能有一个WHERE
-
+
SELECT "department_name", "user_count" FROM (
SELECT
"u"."DEPARTMENT" AS "department_name",
@@ -133,12 +174,22 @@ template:
GROUP BY "u"."DEPARTMENT"
ORDER BY "department_name"
)
- WHERE ROWNUM <= 100 -- 外层限制(确保最终结果可控)
+ WHERE ROWNUM <= 100 -- 正确,在外层限制数量(确保最终结果可控)
+
+
+ SELECT
+ "u"."DEPARTMENT" AS "department_name",
+ count(*) AS "user_count"
+ FROM "PUBLIC"."USERS" "u"
+ WHERE "u"."status" = 1
+ GROUP BY "u"."DEPARTMENT"
+ ORDER BY "department_name"
+ FETCH FIRST 100 ROWS ONLY
- example_engine: Oracle 19c
+ example_engine: Oracle 11g
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: |
diff --git a/backend/templates/template.yaml b/backend/templates/template.yaml
index 7e15db29..def665e6 100644
--- a/backend/templates/template.yaml
+++ b/backend/templates/template.yaml
@@ -6,14 +6,37 @@ template:
{data_training}
sql:
+ process_check: |
+
+ 1. 分析用户问题,确定查询需求
+ 2. 根据表结构生成基础SQL
+ 3. 强制检查:应用数据量限制规则
+ 4. 应用其他规则(引号、别名等)
+ 5. 强制检查:检查语法是否正确?
+ 6. 确定图表类型
+ 7. 返回JSON结果
+
query_limit: |
-
- 1. 必须遵守:所有生成的SQL必须包含数据量限制
- 2. 默认限制:1000条(除非用户明确指定其他数量)
+
+ 数据量限制策略(必须严格遵守 - 零容忍)
+
+ 所有生成的SQL必须包含数据量限制,这是强制要求
+ 默认限制:1000条(除非用户明确指定其他数量)
+ 忘记添加数据量限制是不可接受的错误
+
+
+
+ 如果生成的SQL没有数据量限制,必须重新生成
+ 在最终返回前必须验证限制是否存在
+
no_query_limit: |
-
- 如果没有指定数据条数的限制,则查询的SQL默认返回全部数据
+
+ 数据量限制策略(必须严格遵守)
+
+ 默认不限制数据量,返回全部数据(除非用户明确指定其他数量)
+ 不要臆测场景可能需要的数据量限制,以用户明确指定的数量为准
+
system: |
@@ -27,9 +50,10 @@ template:
:提供一组SQL示例,你可以参考这些示例来生成你的回答,其中内是提问,内是对于该提问的解释或者对应应该回答的SQL示例。
若有块,它会提供一组,可能会是额外添加的背景信息,或者是额外的生成SQL的要求,请结合额外信息或要求后生成你的回答。
用户的提问在内,内则会提供上次执行你提供的SQL时会出现的错误信息,内的会告诉你用户当前提问的时间
+ 你必须遵守内规定的生成SQL规则
+ 你必须遵守内规定的检查步骤生成你的回答
- 你必须遵守以下规则:
请使用语言:{lang} 回答,若有深度思考过程,则思考过程也需要使用 {lang} 输出
@@ -90,6 +114,8 @@ template:
+ {process_check}
+
{basic_sql_examples}
@@ -369,6 +395,8 @@ template:
### 以往提问:
{old_questions}
+
+ /no_think
analysis:
system: |