perf: improve generate Oracle SQL

This commit is contained in:
ulleo
2025-11-25 15:52:51 +08:00
committed by ulleo
parent 8f794279d7
commit 7b3b45e374
3 changed files with 144 additions and 60 deletions
+16 -11
View File
@@ -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 @@ class AiModelQuestion(BaseModel):
'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,
+94 -43
View File
@@ -1,4 +1,18 @@
template:
process_check: |
<SQL-Generation-Process>
<step>1. 分析用户问题,确定查询需求</step>
<step>2. 根据表结构生成基础SQL</step>
<step>3. <strong>强制检查:SQL是否包含GROUP BY/聚合函数?</strong></step>
<step>4. <strong>如果是GROUP BY查询:必须使用外层查询结构包裹</strong></step>
<step>5. <strong>强制检查:应用数据量限制规则</strong></step>
<step>6. 应用其他规则(引号、别名等)</step>
<step>7. <strong>最终验证:GROUP BY查询的ROWNUM位置是否正确?</strong></step>
<step>8. <strong>强制检查:检查语法是否正确?</strong></step>
<step>9. 确定图表类型</step>
<step>10. 返回JSON结果</step>
</SQL-Generation-Process>
quot_rule: |
<rule>
必须对数据库名、表名、字段名、别名外层加双引号(")。
@@ -10,42 +24,61 @@ template:
</rule>
limit_rule: |
<rule priority="high">
当需要限制行数时:
1. 12c以下版本必须使用ROWNUM语法
2. 12c+版本推荐使用FETCH FIRST语法
<note>
版本适配:
- Oracle 12c以下:必须使用 WHERE ROWNUM <= N
- Oracle 12c+:推荐使用 FETCH FIRST N ROWS ONLY
</note>
<note>
<strong>重要:ROWNUM必须放在正确的位置,避免语法错误</strong>
1. <strong>单层查询</strong>:ROWNUM直接跟在WHERE子句后
<template>SELECT ... FROM table WHERE conditions AND ROWNUM <= N</template>
2. <strong>多层查询</strong>:ROWNUM只能放在最外层
<template>
SELECT ... FROM (
SELECT ... FROM table WHERE conditions GROUP BY ...
) WHERE ROWNUM <= N -- 正确:在最外层
</template>
3. <strong>禁止的错误写法</strong>:
<error-example>
SELECT ... FROM table
WHERE conditions
GROUP BY ...
ORDER BY ...
WHERE ROWNUM <= N -- 错误:不能有多个WHERE
</error-example>
4. <strong>正确顺序</strong>:WHERE → GROUP BY → HAVING → ORDER BY → ROWNUM
5. <strong>括号位置</strong>:从内层SELECT开始到内层结束都要括起来
<correct>
SELECT ... FROM (
-- 内层完整查询(包含自己的SELECT、FROM、WHERE、GROUP BY、ORDER BY)
SELECT columns FROM table WHERE conditions GROUP BY ... ORDER BY ...
) alias WHERE ROWNUM <= N
</correct>
</note>
<rule priority="critical" id="oracle-version-handling">
<title>Oracle版本语法适配</title>
<decision-flow>
<condition>如果db-engine版本号小于12</condition>
<then>必须使用ROWNUM语法</then>
<condition>如果db-engine版本号大于等于12</condition>
<then>推荐使用FETCH FIRST语法</then>
</decision-flow>
</rule>
<rule priority="critical" id="oracle-FETCH-FIRST-syntax-rule">
<title>Oracle数据库 FETCH FIRST 语法规范</title>
<description>若使用 FETCH FIRST 语法,则必须遵循该规范</description>
<syntax-rule>
<template>SELECT ... FROM table WHERE conditions FETCH FIRST N ROWS ONLY</template>
</syntax-rule>
</rule>
<rule priority="critical" id="oracle-ROWNUM-syntax-rule">
<title>Oracle数据库ROWNUM语法规范</title>
<description>若使用ROWNUM语法,则必须遵循该规范</description>
<syntax-rules>
<syntax-rule>
<rule-category>简单查询</rule-category>
<template>SELECT ... FROM table WHERE conditions AND ROWNUM <= N</template>
</syntax-rule>
<syntax-rule>
<rule-category>语法禁区</rule-category>
<prohibited>
- 禁止多个WHERE子句
- 禁止ROWNUM在GROUP BY内层(影响分组结果)
- 禁止括号不完整
</prohibited>
</syntax-rule>
</syntax-rules>
</rule>
<rule priority="critical" id="oracle-groupby-rownum">
<title>GROUP BY查询的ROWNUM强制规范(必须严格遵守)</title>
<requirement level="must">所有包含GROUP BY或聚合函数的查询必须使用外层查询结构</requirement>
<requirement level="must">ROWNUM必须放在最外层查询的WHERE子句中</requirement>
<decision-flow>
<condition>如果SQL包含GROUP BY、COUNT、SUM等聚合函数</condition>
<action>必须使用:SELECT ... FROM (内层完整查询) WHERE ROWNUM <= N</action>
<condition>否则(简单查询)</condition>
<action>可以使用:SELECT ... FROM table WHERE conditions AND ROWNUM <= N</action>
</decision-flow>
<error-example>
-- 错误:ROWNUM在内层影响分组结果
SELECT ... GROUP BY ... WHERE ROWNUM <= N
</error-example>
<correct-example>
-- 正确:ROWNUM在外层
SELECT ... FROM (SELECT ... GROUP BY ...) WHERE ROWNUM <= N
</correct-example>
</rule>
other_rule: |
@@ -73,7 +106,7 @@ template:
SELECT "订单ID", "金额" FROM "TEST"."ORDERS" "t1" WHERE ROWNUM <= 100 -- 错误:缺少英文别名
SELECT COUNT("订单ID") FROM "TEST"."ORDERS" "t1" -- 错误:函数未加别名
</output-bad>
<output-good>
<output-good version="12c-below">
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" -- 错误:百分比格式错误
</output-bad>
<output-good>
<output-good version="12c-below">
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
</output-good>
<output-good version="12c+">
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
</output-good>
</example>
<example>
@@ -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"
</output-bad>
<output-bad>
SELECT "department_name", "user_count" FROM
@@ -123,7 +164,7 @@ template:
ORDER BY "department_name"
WHERE ROWNUM <= 100 -- 错误:语法错误,同级内只能有一个WHERE
</output-bad>
<output-good>
<output-good version="12c-below">
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 -- 正确,在外层限制数量(确保最终结果可控)
</output-good>
<output-good version="12c+">
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
</output-good>
</example>
</basic-examples>
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: |
+34 -6
View File
@@ -6,14 +6,37 @@ template:
{data_training}
sql:
process_check: |
<SQL-Generation-Process>
<step>1. 分析用户问题,确定查询需求</step>
<step>2. 根据表结构生成基础SQL</step>
<step>3. <strong>强制检查:应用数据量限制规则</strong></step>
<step>4. 应用其他规则(引号、别名等)</step>
<step>5. <strong>强制检查:检查语法是否正确?</strong></step>
<step>6. 确定图表类型</step>
<step>7. 返回JSON结果</step>
</SQL-Generation-Process>
query_limit: |
<rule priority="high">
1. <strong>必须遵守</strong>:所有生成的SQL必须包含数据量限制
2. <strong>默认限制</strong>:1000条(除非用户明确指定其他数量)
<rule priority="critical" id="data-limit-policy">
<title>数据量限制策略(必须严格遵守 - 零容忍)</title>
<requirements>
<requirement level="must-zero-tolerance">所有生成的SQL必须包含数据量限制,这是强制要求</requirement>
<requirement level="must">默认限制:1000条(除非用户明确指定其他数量)</requirement>
<requirement level="must">忘记添加数据量限制是不可接受的错误</requirement>
</requirements>
<enforcement>
<action>如果生成的SQL没有数据量限制,必须重新生成</action>
<action>在最终返回前必须验证限制是否存在</action>
</enforcement>
</rule>
no_query_limit: |
<rule priority="high">
如果没有指定数据条数的限制,则查询的SQL默认返回全部数据
<rule priority="critical" id="data-limit-policy">
<title>数据量限制策略(必须严格遵守)</title>
<requirements>
<requirement>默认不限制数据量,返回全部数据(除非用户明确指定其他数量)</requirement>
<requirement>不要臆测场景可能需要的数据量限制,以用户明确指定的数量为准</requirement>
</requirements>
</rule>
system: |
<Instruction>
@@ -27,9 +50,10 @@ template:
<sql-examples>:提供一组SQL示例,你可以参考这些示例来生成你的回答,其中<question>内是提问,<suggestion-answer>内是对于该<question>提问的解释或者对应应该回答的SQL示例。
若有<Other-Infos>块,它会提供一组<content>,可能会是额外添加的背景信息,或者是额外的生成SQL的要求,请结合额外信息或要求后生成你的回答。
用户的提问在<user-question>内,<error-msg>内则会提供上次执行你提供的SQL时会出现的错误信息,<background-infos>内的<current-time>会告诉你用户当前提问的时间
你必须遵守<Rules>内规定的生成SQL规则
你必须遵守<SQL-Generation-Process>内规定的检查步骤生成你的回答
</Instruction>
你必须遵守以下规则:
<Rules>
<rule>
请使用语言:{lang} 回答,若有深度思考过程,则思考过程也需要使用 {lang} 输出
@@ -90,6 +114,8 @@ template:
</rule>
</Rules>
{process_check}
{basic_sql_examples}
<example>
@@ -369,6 +395,8 @@ template:
### 以往提问:
{old_questions}
/no_think
analysis:
system: |
<Instruction>