Skip to content

Commit 7b3b45e

Browse files
committed
perf: improve generate Oracle SQL
1 parent 8f79427 commit 7b3b45e

File tree

3 files changed

+144
-60
lines changed

3 files changed

+144
-60
lines changed

backend/apps/chat/models/chat_model.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,12 @@ class AiModelQuestion(BaseModel):
185185

186186
def sql_sys_question(self, db_type: Union[str, DB], enable_query_limit: bool = True):
187187
_sql_template = get_sql_example_template(db_type)
188-
_query_limit = get_sql_template()['query_limit'] if enable_query_limit else get_sql_template()['no_query_limit']
189-
_base_sql_rules = _sql_template['quot_rule'] + _query_limit + _sql_template['limit_rule'] + _sql_template['other_rule']
188+
_base_template = get_sql_template()
189+
_process_check = _sql_template.get('process_check') if _sql_template.get('process_check') else _base_template[
190+
'process_check']
191+
_query_limit = _base_template['query_limit'] if enable_query_limit else _base_template['no_query_limit']
192+
_base_sql_rules = _sql_template['quot_rule'] + _query_limit + _sql_template['limit_rule'] + _sql_template[
193+
'other_rule']
190194
_sql_examples = _sql_template['basic_example']
191195
_example_engine = _sql_template['example_engine']
192196
_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
195199
'example_answer_2']
196200
_example_answer_3 = _sql_template['example_answer_3_with_limit'] if enable_query_limit else _sql_template[
197201
'example_answer_3']
198-
return get_sql_template()['system'].format(engine=self.engine, schema=self.db_schema, question=self.question,
199-
lang=self.lang, terminologies=self.terminologies,
200-
data_training=self.data_training, custom_prompt=self.custom_prompt,
201-
base_sql_rules=_base_sql_rules,
202-
basic_sql_examples=_sql_examples,
203-
example_engine=_example_engine,
204-
example_answer_1=_example_answer_1,
205-
example_answer_2=_example_answer_2,
206-
example_answer_3=_example_answer_3)
202+
return _base_template['system'].format(engine=self.engine, schema=self.db_schema, question=self.question,
203+
lang=self.lang, terminologies=self.terminologies,
204+
data_training=self.data_training, custom_prompt=self.custom_prompt,
205+
process_check=_process_check,
206+
base_sql_rules=_base_sql_rules,
207+
basic_sql_examples=_sql_examples,
208+
example_engine=_example_engine,
209+
example_answer_1=_example_answer_1,
210+
example_answer_2=_example_answer_2,
211+
example_answer_3=_example_answer_3)
207212

208213
def sql_user_question(self, current_time: str):
209214
return get_sql_template()['user'].format(engine=self.engine, schema=self.db_schema, question=self.question,

backend/templates/sql_examples/Oracle.yaml

Lines changed: 94 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11
template:
2+
process_check: |
3+
<SQL-Generation-Process>
4+
<step>1. 分析用户问题,确定查询需求</step>
5+
<step>2. 根据表结构生成基础SQL</step>
6+
<step>3. <strong>强制检查:SQL是否包含GROUP BY/聚合函数?</strong></step>
7+
<step>4. <strong>如果是GROUP BY查询:必须使用外层查询结构包裹</strong></step>
8+
<step>5. <strong>强制检查:应用数据量限制规则</strong></step>
9+
<step>6. 应用其他规则(引号、别名等)</step>
10+
<step>7. <strong>最终验证:GROUP BY查询的ROWNUM位置是否正确?</strong></step>
11+
<step>8. <strong>强制检查:检查语法是否正确?</strong></step>
12+
<step>9. 确定图表类型</step>
13+
<step>10. 返回JSON结果</step>
14+
</SQL-Generation-Process>
15+
216
quot_rule: |
317
<rule>
418
必须对数据库名、表名、字段名、别名外层加双引号(")。
@@ -10,42 +24,61 @@ template:
1024
</rule>
1125
1226
limit_rule: |
13-
<rule priority="high">
14-
当需要限制行数时:
15-
1. 12c以下版本必须使用ROWNUM语法
16-
2. 12c+版本推荐使用FETCH FIRST语法
17-
<note>
18-
版本适配:
19-
- Oracle 12c以下:必须使用 WHERE ROWNUM <= N
20-
- Oracle 12c+:推荐使用 FETCH FIRST N ROWS ONLY
21-
</note>
22-
<note>
23-
<strong>重要:ROWNUM必须放在正确的位置,避免语法错误</strong>
24-
1. <strong>单层查询</strong>:ROWNUM直接跟在WHERE子句后
25-
<template>SELECT ... FROM table WHERE conditions AND ROWNUM <= N</template>
26-
2. <strong>多层查询</strong>:ROWNUM只能放在最外层
27-
<template>
28-
SELECT ... FROM (
29-
SELECT ... FROM table WHERE conditions GROUP BY ...
30-
) WHERE ROWNUM <= N -- 正确:在最外层
31-
</template>
32-
3. <strong>禁止的错误写法</strong>:
33-
<error-example>
34-
SELECT ... FROM table
35-
WHERE conditions
36-
GROUP BY ...
37-
ORDER BY ...
38-
WHERE ROWNUM <= N -- 错误:不能有多个WHERE
39-
</error-example>
40-
4. <strong>正确顺序</strong>:WHERE → GROUP BY → HAVING → ORDER BY → ROWNUM
41-
5. <strong>括号位置</strong>:从内层SELECT开始到内层结束都要括起来
42-
<correct>
43-
SELECT ... FROM (
44-
-- 内层完整查询(包含自己的SELECT、FROM、WHERE、GROUP BY、ORDER BY)
45-
SELECT columns FROM table WHERE conditions GROUP BY ... ORDER BY ...
46-
) alias WHERE ROWNUM <= N
47-
</correct>
48-
</note>
27+
<rule priority="critical" id="oracle-version-handling">
28+
<title>Oracle版本语法适配</title>
29+
<decision-flow>
30+
<condition>如果db-engine版本号小于12</condition>
31+
<then>必须使用ROWNUM语法</then>
32+
<condition>如果db-engine版本号大于等于12</condition>
33+
<then>推荐使用FETCH FIRST语法</then>
34+
</decision-flow>
35+
</rule>
36+
<rule priority="critical" id="oracle-FETCH-FIRST-syntax-rule">
37+
<title>Oracle数据库 FETCH FIRST 语法规范</title>
38+
<description>若使用 FETCH FIRST 语法,则必须遵循该规范</description>
39+
<syntax-rule>
40+
<template>SELECT ... FROM table WHERE conditions FETCH FIRST N ROWS ONLY</template>
41+
</syntax-rule>
42+
</rule>
43+
<rule priority="critical" id="oracle-ROWNUM-syntax-rule">
44+
<title>Oracle数据库ROWNUM语法规范</title>
45+
<description>若使用ROWNUM语法,则必须遵循该规范</description>
46+
<syntax-rules>
47+
<syntax-rule>
48+
<rule-category>简单查询</rule-category>
49+
<template>SELECT ... FROM table WHERE conditions AND ROWNUM <= N</template>
50+
</syntax-rule>
51+
<syntax-rule>
52+
<rule-category>语法禁区</rule-category>
53+
<prohibited>
54+
- 禁止多个WHERE子句
55+
- 禁止ROWNUM在GROUP BY内层(影响分组结果)
56+
- 禁止括号不完整
57+
</prohibited>
58+
</syntax-rule>
59+
</syntax-rules>
60+
</rule>
61+
<rule priority="critical" id="oracle-groupby-rownum">
62+
<title>GROUP BY查询的ROWNUM强制规范(必须严格遵守)</title>
63+
<requirement level="must">所有包含GROUP BY或聚合函数的查询必须使用外层查询结构</requirement>
64+
<requirement level="must">ROWNUM必须放在最外层查询的WHERE子句中</requirement>
65+
66+
<decision-flow>
67+
<condition>如果SQL包含GROUP BY、COUNT、SUM等聚合函数</condition>
68+
<action>必须使用:SELECT ... FROM (内层完整查询) WHERE ROWNUM <= N</action>
69+
<condition>否则(简单查询)</condition>
70+
<action>可以使用:SELECT ... FROM table WHERE conditions AND ROWNUM <= N</action>
71+
</decision-flow>
72+
73+
<error-example>
74+
-- 错误:ROWNUM在内层影响分组结果
75+
SELECT ... GROUP BY ... WHERE ROWNUM <= N
76+
</error-example>
77+
78+
<correct-example>
79+
-- 正确:ROWNUM在外层
80+
SELECT ... FROM (SELECT ... GROUP BY ...) WHERE ROWNUM <= N
81+
</correct-example>
4982
</rule>
5083
5184
other_rule: |
@@ -73,7 +106,7 @@ template:
73106
SELECT "订单ID", "金额" FROM "TEST"."ORDERS" "t1" WHERE ROWNUM <= 100 -- 错误:缺少英文别名
74107
SELECT COUNT("订单ID") FROM "TEST"."ORDERS" "t1" -- 错误:函数未加别名
75108
</output-bad>
76-
<output-good>
109+
<output-good version="12c-below">
77110
SELECT
78111
"t1"."订单ID" AS "order_id",
79112
"t1"."金额" AS "amount",
@@ -90,14 +123,22 @@ template:
90123
SELECT DATE, status FROM PUBLIC.USERS -- 错误:未处理关键字和引号
91124
SELECT "DATE", ROUND(active_ratio) FROM "PUBLIC"."USERS" -- 错误:百分比格式错误
92125
</output-bad>
93-
<output-good>
126+
<output-good version="12c-below">
94127
SELECT
95128
"u"."DATE" AS "create_date",
96129
TO_CHAR("u"."active_ratio" * 100, '990.99') || '%' AS "active_percent"
97130
FROM "PUBLIC"."USERS" "u"
98131
WHERE "u"."status" = 1
99132
AND ROWNUM <= 1000
100133
</output-good>
134+
<output-good version="12c+">
135+
SELECT
136+
"u"."DATE" AS "create_date",
137+
TO_CHAR("u"."active_ratio" * 100, '990.99') || '%' AS "active_percent"
138+
FROM "PUBLIC"."USERS" "u"
139+
WHERE "u"."status" = 1
140+
FETCH FIRST 1000 ROWS ONLY
141+
</output-good>
101142
</example>
102143
103144
<example>
@@ -108,9 +149,9 @@ template:
108149
count(*) AS "user_count"
109150
FROM "PUBLIC"."USERS" "u"
110151
WHERE "u"."status" = 1
111-
AND ROWNUM <= 100
152+
AND ROWNUM <= 100 -- 严重错误:影响分组结果!
112153
GROUP BY "u"."DEPARTMENT"
113-
ORDER BY "department_name" -- 错误:ROWNUM 应当写在最外层,这样会导致查询结果条数比实际数据的数量少
154+
ORDER BY "department_name"
114155
</output-bad>
115156
<output-bad>
116157
SELECT "department_name", "user_count" FROM
@@ -123,7 +164,7 @@ template:
123164
ORDER BY "department_name"
124165
WHERE ROWNUM <= 100 -- 错误:语法错误,同级内只能有一个WHERE
125166
</output-bad>
126-
<output-good>
167+
<output-good version="12c-below">
127168
SELECT "department_name", "user_count" FROM (
128169
SELECT
129170
"u"."DEPARTMENT" AS "department_name",
@@ -133,12 +174,22 @@ template:
133174
GROUP BY "u"."DEPARTMENT"
134175
ORDER BY "department_name"
135176
)
136-
WHERE ROWNUM <= 100 -- 外层限制(确保最终结果可控)
177+
WHERE ROWNUM <= 100 -- 正确,在外层限制数量(确保最终结果可控)
178+
</output-good>
179+
<output-good version="12c+">
180+
SELECT
181+
"u"."DEPARTMENT" AS "department_name",
182+
count(*) AS "user_count"
183+
FROM "PUBLIC"."USERS" "u"
184+
WHERE "u"."status" = 1
185+
GROUP BY "u"."DEPARTMENT"
186+
ORDER BY "department_name"
187+
FETCH FIRST 100 ROWS ONLY
137188
</output-good>
138189
</example>
139190
</basic-examples>
140191
141-
example_engine: Oracle 19c
192+
example_engine: Oracle 11g
142193
example_answer_1: |
143194
{"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"}
144195
example_answer_1_with_limit: |

backend/templates/template.yaml

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,37 @@ template:
66
77
{data_training}
88
sql:
9+
process_check: |
10+
<SQL-Generation-Process>
11+
<step>1. 分析用户问题,确定查询需求</step>
12+
<step>2. 根据表结构生成基础SQL</step>
13+
<step>3. <strong>强制检查:应用数据量限制规则</strong></step>
14+
<step>4. 应用其他规则(引号、别名等)</step>
15+
<step>5. <strong>强制检查:检查语法是否正确?</strong></step>
16+
<step>6. 确定图表类型</step>
17+
<step>7. 返回JSON结果</step>
18+
</SQL-Generation-Process>
919
query_limit: |
10-
<rule priority="high">
11-
1. <strong>必须遵守</strong>:所有生成的SQL必须包含数据量限制
12-
2. <strong>默认限制</strong>:1000条(除非用户明确指定其他数量)
20+
<rule priority="critical" id="data-limit-policy">
21+
<title>数据量限制策略(必须严格遵守 - 零容忍)</title>
22+
<requirements>
23+
<requirement level="must-zero-tolerance">所有生成的SQL必须包含数据量限制,这是强制要求</requirement>
24+
<requirement level="must">默认限制:1000条(除非用户明确指定其他数量)</requirement>
25+
<requirement level="must">忘记添加数据量限制是不可接受的错误</requirement>
26+
</requirements>
27+
28+
<enforcement>
29+
<action>如果生成的SQL没有数据量限制,必须重新生成</action>
30+
<action>在最终返回前必须验证限制是否存在</action>
31+
</enforcement>
1332
</rule>
1433
no_query_limit: |
15-
<rule priority="high">
16-
如果没有指定数据条数的限制,则查询的SQL默认返回全部数据
34+
<rule priority="critical" id="data-limit-policy">
35+
<title>数据量限制策略(必须严格遵守)</title>
36+
<requirements>
37+
<requirement>默认不限制数据量,返回全部数据(除非用户明确指定其他数量)</requirement>
38+
<requirement>不要臆测场景可能需要的数据量限制,以用户明确指定的数量为准</requirement>
39+
</requirements>
1740
</rule>
1841
system: |
1942
<Instruction>
@@ -27,9 +50,10 @@ template:
2750
<sql-examples>:提供一组SQL示例,你可以参考这些示例来生成你的回答,其中<question>内是提问,<suggestion-answer>内是对于该<question>提问的解释或者对应应该回答的SQL示例。
2851
若有<Other-Infos>块,它会提供一组<content>,可能会是额外添加的背景信息,或者是额外的生成SQL的要求,请结合额外信息或要求后生成你的回答。
2952
用户的提问在<user-question>内,<error-msg>内则会提供上次执行你提供的SQL时会出现的错误信息,<background-infos>内的<current-time>会告诉你用户当前提问的时间
53+
你必须遵守<Rules>内规定的生成SQL规则
54+
你必须遵守<SQL-Generation-Process>内规定的检查步骤生成你的回答
3055
</Instruction>
3156
32-
你必须遵守以下规则:
3357
<Rules>
3458
<rule>
3559
请使用语言:{lang} 回答,若有深度思考过程,则思考过程也需要使用 {lang} 输出
@@ -90,6 +114,8 @@ template:
90114
</rule>
91115
</Rules>
92116
117+
{process_check}
118+
93119
{basic_sql_examples}
94120
95121
<example>
@@ -369,6 +395,8 @@ template:
369395
370396
### 以往提问:
371397
{old_questions}
398+
399+
/no_think
372400
analysis:
373401
system: |
374402
<Instruction>

0 commit comments

Comments
 (0)