mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
fix(chat): constrain SQL row-limit placement to outermost query in prompt templates (#1202)
The row-limit policy in query_limit/no_query_limit did not specify WHERE the limit should be applied, so LLMs could put LIMIT/ROWNUM/TOP inside subqueries, truncating the data feeding aggregation (limiting accessed rows instead of the final result set). - query_limit/no_query_limit: limit must be applied only to the outermost query; never inside subqueries, derived tables or CTEs; add conditional per-group top-N note (window functions where supported) - process_check (template.yaml + Oracle override): step 4 now verifies limit placement - sql_examples: add nested-aggregation bad/good examples for all 11 engines showing the limit on the outer query only - Oracle: fix invalid GROUP BY...WHERE ROWNUM example and wrong ROWNUM-before-ORDER BY few-shot answers (wrap with outer query)
This commit is contained in:
@@ -71,6 +71,27 @@ template:
|
||||
FETCH FIRST 1000 ROWS ONLY
|
||||
</output-good>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<input>统计订单表 TEST.ORDERS 中2024年每个客户的消费总金额,返回金额最高的前100名客户</input>
|
||||
<output-bad>
|
||||
SELECT "t"."customer_id" AS "customer_id", SUM("t"."amount") AS "total_amount"
|
||||
FROM (SELECT "customer_id", "amount" FROM "TEST"."ORDERS" WHERE "create_time" >= '2024-01-01' LIMIT 100) "t"
|
||||
GROUP BY "t"."customer_id"
|
||||
-- 严重错误:LIMIT加在了内层子查询中,聚合只基于被截断的100行数据计算,结果错误!
|
||||
</output-bad>
|
||||
<output-good>
|
||||
SELECT
|
||||
"o"."customer_id" AS "customer_id",
|
||||
SUM("o"."amount") AS "total_amount"
|
||||
FROM "TEST"."ORDERS" "o"
|
||||
WHERE "o"."create_time" >= '2024-01-01'
|
||||
GROUP BY "o"."customer_id"
|
||||
ORDER BY "total_amount" DESC
|
||||
LIMIT 100
|
||||
-- 正确:聚合基于完整数据计算,LIMIT只限制最终返回结果的行数,且只出现在最外层查询
|
||||
</output-good>
|
||||
</example>
|
||||
</basic-examples>
|
||||
|
||||
example_engine: AWS Redshift 1.0
|
||||
|
||||
@@ -74,6 +74,27 @@ template:
|
||||
LIMIT 5
|
||||
</output-good>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<input>统计订单表 default.orders 中2024年每个客户的消费总金额,返回金额最高的前100名客户</input>
|
||||
<output-bad>
|
||||
SELECT "t"."customer_id" AS "customer_id", SUM("t"."amount") AS "total_amount"
|
||||
FROM (SELECT "customer_id", "amount" FROM "default"."orders" WHERE "create_time" >= '2024-01-01' LIMIT 100) "t"
|
||||
GROUP BY "t"."customer_id"
|
||||
-- 严重错误:LIMIT加在了内层子查询中,聚合只基于被截断的100行数据计算,结果错误!
|
||||
</output-bad>
|
||||
<output-good>
|
||||
SELECT
|
||||
"o"."customer_id" AS "customer_id",
|
||||
SUM("o"."amount") AS "total_amount"
|
||||
FROM "default"."orders" "o"
|
||||
WHERE "o"."create_time" >= '2024-01-01'
|
||||
GROUP BY "o"."customer_id"
|
||||
ORDER BY "total_amount" DESC
|
||||
LIMIT 100
|
||||
-- 正确:聚合基于完整数据计算,LIMIT只限制最终返回结果的行数,且只出现在最外层查询
|
||||
</output-good>
|
||||
</example>
|
||||
</basic-examples>
|
||||
|
||||
example_engine: ClickHouse 23.3
|
||||
|
||||
@@ -72,6 +72,27 @@ template:
|
||||
LIMIT 0, 1000 -- 达梦兼容写法
|
||||
</output-good>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<input>统计订单表 TEST.ORDERS 中2024年每个客户的消费总金额,返回金额最高的前100名客户</input>
|
||||
<output-bad>
|
||||
SELECT "t"."customer_id" AS "customer_id", SUM("t"."amount") AS "total_amount"
|
||||
FROM (SELECT "customer_id", "amount" FROM "TEST"."ORDERS" WHERE "create_time" >= '2024-01-01' LIMIT 100) "t"
|
||||
GROUP BY "t"."customer_id"
|
||||
-- 严重错误:LIMIT加在了内层子查询中,聚合只基于被截断的100行数据计算,结果错误!
|
||||
</output-bad>
|
||||
<output-good>
|
||||
SELECT
|
||||
"o"."customer_id" AS "customer_id",
|
||||
SUM("o"."amount") AS "total_amount"
|
||||
FROM "TEST"."ORDERS" "o"
|
||||
WHERE "o"."create_time" >= '2024-01-01'
|
||||
GROUP BY "o"."customer_id"
|
||||
ORDER BY "total_amount" DESC
|
||||
LIMIT 100
|
||||
-- 正确:聚合基于完整数据计算,LIMIT只限制最终返回结果的行数,且只出现在最外层查询
|
||||
</output-good>
|
||||
</example>
|
||||
</basic-examples>
|
||||
|
||||
example_engine: DM Database 8
|
||||
|
||||
@@ -74,6 +74,27 @@ template:
|
||||
LIMIT 1000
|
||||
</output-good>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<input>统计订单表 test.orders 中2024年每个客户的消费总金额,返回金额最高的前100名客户</input>
|
||||
<output-bad>
|
||||
SELECT `t`.`customer_id` AS `customer_id`, SUM(`t`.`amount`) AS `total_amount`
|
||||
FROM (SELECT `customer_id`, `amount` FROM `test`.`orders` WHERE `create_time` >= '2024-01-01' LIMIT 100) `t`
|
||||
GROUP BY `t`.`customer_id`
|
||||
-- 严重错误:LIMIT加在了内层子查询中,聚合只基于被截断的100行数据计算,结果错误!
|
||||
</output-bad>
|
||||
<output-good>
|
||||
SELECT
|
||||
`o`.`customer_id` AS `customer_id`,
|
||||
SUM(`o`.`amount`) AS `total_amount`
|
||||
FROM `test`.`orders` `o`
|
||||
WHERE `o`.`create_time` >= '2024-01-01'
|
||||
GROUP BY `o`.`customer_id`
|
||||
ORDER BY `total_amount` DESC
|
||||
LIMIT 100
|
||||
-- 正确:聚合基于完整数据计算,LIMIT只限制最终返回结果的行数,且只出现在最外层查询
|
||||
</output-good>
|
||||
</example>
|
||||
</basic-examples>
|
||||
|
||||
example_engine: Apache Doris 2.0
|
||||
|
||||
@@ -88,6 +88,27 @@ template:
|
||||
LIMIT 5
|
||||
</output-good>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<input>统计 logs-* 索引中最近一天各个客户端IP的日志数量,返回数量最多的前100个IP</input>
|
||||
<output-bad>
|
||||
SELECT "t"."host.ip" AS "client_ip", COUNT("t"."message") AS "log_count"
|
||||
FROM (SELECT "host.ip", "message" FROM "logs-*" LIMIT 100) "t"
|
||||
GROUP BY "t"."host.ip"
|
||||
-- 严重错误:内层LIMIT导致聚合只基于被截断的100行数据计算,结果错误!Elasticsearch SQL也不支持FROM子查询
|
||||
</output-bad>
|
||||
<output-good>
|
||||
SELECT
|
||||
"l"."host.ip" AS "client_ip",
|
||||
COUNT("l"."message") AS "log_count"
|
||||
FROM "logs-*" "l"
|
||||
WHERE CAST("l"."@timestamp" AS TIMESTAMP) > DATE_SUB(NOW(), INTERVAL 1 DAY)
|
||||
GROUP BY "l"."host.ip"
|
||||
ORDER BY "log_count" DESC
|
||||
LIMIT 100
|
||||
-- 正确:聚合基于完整数据计算,LIMIT只限制最终返回结果的行数,且只出现在整个查询的最外层
|
||||
</output-good>
|
||||
</example>
|
||||
</basic-examples>
|
||||
|
||||
example_engine: Elasticsearch SQL 8.9
|
||||
|
||||
@@ -71,6 +71,27 @@ template:
|
||||
WHERE `u`.`status` = 1
|
||||
</output-good>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<input>统计订单表 ods.orders 中2024年每个客户的消费总金额,返回金额最高的前100名客户</input>
|
||||
<output-bad>
|
||||
SELECT `t`.`customer_id` AS `customer_id`, SUM(`t`.`amount`) AS `total_amount`
|
||||
FROM (SELECT `customer_id`, `amount` FROM `ods`.`orders` WHERE YEAR(`create_time`) = 2024 LIMIT 100) `t`
|
||||
GROUP BY `t`.`customer_id`
|
||||
-- 严重错误:LIMIT加在了内层子查询中,聚合只基于被截断的100行数据计算,结果错误!
|
||||
</output-bad>
|
||||
<output-good>
|
||||
SELECT
|
||||
`o`.`customer_id` AS `customer_id`,
|
||||
SUM(`o`.`amount`) AS `total_amount`
|
||||
FROM `ods`.`orders` `o`
|
||||
WHERE YEAR(`o`.`create_time`) = 2024
|
||||
GROUP BY `o`.`customer_id`
|
||||
ORDER BY `total_amount` DESC
|
||||
LIMIT 100
|
||||
-- 正确:聚合基于完整数据计算,LIMIT只限制最终返回结果的行数,且只出现在最外层查询
|
||||
</output-good>
|
||||
</example>
|
||||
</basic-examples>
|
||||
|
||||
example_engine: Apache Hive 2.X
|
||||
|
||||
@@ -67,6 +67,27 @@ template:
|
||||
WHERE "u"."status" = 1
|
||||
</output-good>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<input>统计订单表 TEST.ORDERS 中2024年每个客户的消费总金额,返回金额最高的前100名客户</input>
|
||||
<output-bad>
|
||||
SELECT "t"."customer_id" AS "customer_id", SUM("t"."amount") AS "total_amount"
|
||||
FROM (SELECT "customer_id", "amount" FROM "TEST"."ORDERS" WHERE "create_time" >= '2024-01-01' LIMIT 100) "t"
|
||||
GROUP BY "t"."customer_id"
|
||||
-- 严重错误:LIMIT加在了内层子查询中,聚合只基于被截断的100行数据计算,结果错误!
|
||||
</output-bad>
|
||||
<output-good>
|
||||
SELECT
|
||||
"o"."customer_id" AS "customer_id",
|
||||
SUM("o"."amount") AS "total_amount"
|
||||
FROM "TEST"."ORDERS" "o"
|
||||
WHERE "o"."create_time" >= '2024-01-01'
|
||||
GROUP BY "o"."customer_id"
|
||||
ORDER BY "total_amount" DESC
|
||||
LIMIT 100
|
||||
-- 正确:聚合基于完整数据计算,LIMIT只限制最终返回结果的行数,且只出现在最外层查询
|
||||
</output-good>
|
||||
</example>
|
||||
</basic-examples>
|
||||
|
||||
example_engine: Kingbase V8
|
||||
|
||||
@@ -72,6 +72,26 @@ template:
|
||||
OFFSET 0 ROWS FETCH NEXT 1000 ROWS ONLY
|
||||
</output-good>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<input>统计订单表 Sales.Orders 中2024年每个客户的消费总金额,返回金额最高的前100名客户</input>
|
||||
<output-bad>
|
||||
SELECT [t].[customer_id] AS [customer_id], SUM([t].[amount]) AS [total_amount]
|
||||
FROM (SELECT TOP 100 [customer_id], [amount] FROM [Sales].[Orders] WHERE [create_time] >= '2024-01-01') [t]
|
||||
GROUP BY [t].[customer_id]
|
||||
-- 严重错误:TOP加在了内层子查询中,聚合只基于被截断的100行数据计算,结果错误!
|
||||
</output-bad>
|
||||
<output-good>
|
||||
SELECT TOP 100
|
||||
[o].[customer_id] AS [customer_id],
|
||||
SUM([o].[amount]) AS [total_amount]
|
||||
FROM [Sales].[Orders] [o]
|
||||
WHERE [o].[create_time] >= '2024-01-01'
|
||||
GROUP BY [o].[customer_id]
|
||||
ORDER BY [total_amount] DESC
|
||||
-- 正确:TOP只加在最外层查询上,聚合基于完整数据计算,只限制最终返回结果的行数
|
||||
</output-good>
|
||||
</example>
|
||||
</basic-examples>
|
||||
|
||||
example_engine: Microsoft SQL Server 2022
|
||||
|
||||
@@ -63,7 +63,7 @@ template:
|
||||
SELECT `desc`, ROUND(active_ratio*100) FROM `public`.`users` -- 错误:百分比格式错误
|
||||
</output-bad>
|
||||
<output-good>
|
||||
SELECT
|
||||
SELECT
|
||||
`u`.`desc` AS `description`,
|
||||
CONCAT(ROUND(`u`.`active_ratio` * 100, 2), '%') AS `active_percent`
|
||||
FROM `public`.`users` `u`
|
||||
@@ -71,6 +71,27 @@ template:
|
||||
LIMIT 1000
|
||||
</output-good>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<input>统计订单表 test.orders 中2024年每个客户的消费总金额,返回金额最高的前100名客户</input>
|
||||
<output-bad>
|
||||
SELECT `t`.`customer_id` AS `customer_id`, SUM(`t`.`amount`) AS `total_amount`
|
||||
FROM (SELECT `customer_id`, `amount` FROM `test`.`orders` WHERE `create_time` >= '2024-01-01' LIMIT 100) `t`
|
||||
GROUP BY `t`.`customer_id`
|
||||
-- 严重错误:LIMIT加在了内层子查询中,聚合只基于被截断的100行数据计算,结果错误!
|
||||
</output-bad>
|
||||
<output-good>
|
||||
SELECT
|
||||
`o`.`customer_id` AS `customer_id`,
|
||||
SUM(`o`.`amount`) AS `total_amount`
|
||||
FROM `test`.`orders` `o`
|
||||
WHERE `o`.`create_time` >= '2024-01-01'
|
||||
GROUP BY `o`.`customer_id`
|
||||
ORDER BY `total_amount` DESC
|
||||
LIMIT 100
|
||||
-- 正确:聚合基于完整数据计算,LIMIT只限制最终返回结果的行数,且只出现在最外层查询
|
||||
</output-good>
|
||||
</example>
|
||||
</basic-examples>
|
||||
|
||||
example_engine: MySQL 8.0
|
||||
|
||||
@@ -4,7 +4,7 @@ template:
|
||||
<step>1. 分析用户问题,确定查询需求</step>
|
||||
<step>2. 根据表结构生成基础SQL</step>
|
||||
<step>3. <strong>强制检查:逐字验证SQL中使用的表名和字段名是否在<m-schema>中定义,且字符必须完全匹配(包括繁简体、大小写、特殊字符),不得有任何转换。如发现任何不一致,必须重新生成SQL。</strong></step>
|
||||
<step>4. <strong>强制检查:应用数据量限制规则(默认限制或用户指定数量)</strong></step>
|
||||
<step>4. <strong>强制检查:应用数据量限制规则(默认限制或用户指定数量),限制必须位于最外层查询,不得出现在子查询、派生表、CTE内部</strong></step>
|
||||
<step>5. 应用其他规则(引号、别名、格式化等)</step>
|
||||
<step>6. <strong>最终验证:GROUP BY查询的ROWNUM位置是否正确?</strong></step>
|
||||
<step>7. <strong>强制检查:验证SQL语法是否符合<db-engine>规范</strong></step>
|
||||
@@ -110,14 +110,26 @@ template:
|
||||
SELECT COUNT("订单ID") FROM "TEST"."ORDERS" "t1" -- 错误:函数未加别名
|
||||
</output-bad>
|
||||
<output-good version="12c-below">
|
||||
SELECT
|
||||
SELECT "order_id", "amount", "total_orders", "discount_percent" FROM (
|
||||
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"
|
||||
GROUP BY "t1"."订单ID", "t1"."金额", "t1"."折扣率"
|
||||
)
|
||||
WHERE ROWNUM <= 100
|
||||
</output-good>
|
||||
<output-good version="12c+">
|
||||
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"
|
||||
GROUP BY "t1"."订单ID", "t1"."金额", "t1"."折扣率"
|
||||
WHERE ROWNUM <= 100
|
||||
FETCH FIRST 100 ROWS ONLY
|
||||
</output-good>
|
||||
</example>
|
||||
|
||||
@@ -197,11 +209,11 @@ template:
|
||||
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"}
|
||||
{"success":true,"sql":"SELECT \"country_name\", \"continent_name\", \"year\", \"gdp\" FROM (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\") WHERE ROWNUM <= 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' AND ROWNUM <= 1000 ORDER BY \"gdp\" DESC","tables":["sample_country_gdp"],"chart-type":"pie"}
|
||||
{"success":true,"sql":"SELECT \"country_name\", \"gdp\" FROM (SELECT \"country\" AS \"country_name\", \"gdp\" AS \"gdp\" FROM \"Sample_Database\".\"sample_country_gdp\" WHERE \"year\" = '2024' ORDER BY \"gdp\" DESC) WHERE ROWNUM <= 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: |
|
||||
|
||||
@@ -58,13 +58,34 @@ template:
|
||||
SELECT "user", ROUND(active_ratio) FROM "PUBLIC"."USERS" -- 错误:百分比格式错误
|
||||
</output-bad>
|
||||
<output-good>
|
||||
SELECT
|
||||
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>
|
||||
|
||||
<example>
|
||||
<input>统计订单表 TEST.ORDERS 中2024年每个客户的消费总金额,返回金额最高的前100名客户</input>
|
||||
<output-bad>
|
||||
SELECT "t"."customer_id" AS "customer_id", SUM("t"."amount") AS "total_amount"
|
||||
FROM (SELECT "customer_id", "amount" FROM "TEST"."ORDERS" WHERE "create_time" >= '2024-01-01' LIMIT 100) "t"
|
||||
GROUP BY "t"."customer_id"
|
||||
-- 严重错误:LIMIT加在了内层子查询中,聚合只基于被截断的100行数据计算,结果错误!
|
||||
</output-bad>
|
||||
<output-good>
|
||||
SELECT
|
||||
"o"."customer_id" AS "customer_id",
|
||||
SUM("o"."amount") AS "total_amount"
|
||||
FROM "TEST"."ORDERS" "o"
|
||||
WHERE "o"."create_time" >= '2024-01-01'
|
||||
GROUP BY "o"."customer_id"
|
||||
ORDER BY "total_amount" DESC
|
||||
LIMIT 100
|
||||
-- 正确:聚合基于完整数据计算,LIMIT只限制最终返回结果的行数,且只出现在最外层查询
|
||||
</output-good>
|
||||
</example>
|
||||
</basic-examples>
|
||||
|
||||
example_engine: PostgreSQL17.6 (Debian 17.6-1.pgdg12+1)
|
||||
|
||||
@@ -72,6 +72,27 @@ template:
|
||||
LIMIT 1000
|
||||
</output-good>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<input>统计订单表 test.orders 中2024年每个客户的消费总金额,返回金额最高的前100名客户</input>
|
||||
<output-bad>
|
||||
SELECT `t`.`customer_id` AS `customer_id`, SUM(`t`.`amount`) AS `total_amount`
|
||||
FROM (SELECT `customer_id`, `amount` FROM `test`.`orders` WHERE `create_time` >= '2024-01-01' LIMIT 100) `t`
|
||||
GROUP BY `t`.`customer_id`
|
||||
-- 严重错误:LIMIT加在了内层子查询中,聚合只基于被截断的100行数据计算,结果错误!
|
||||
</output-bad>
|
||||
<output-good>
|
||||
SELECT
|
||||
`o`.`customer_id` AS `customer_id`,
|
||||
SUM(`o`.`amount`) AS `total_amount`
|
||||
FROM `test`.`orders` `o`
|
||||
WHERE `o`.`create_time` >= '2024-01-01'
|
||||
GROUP BY `o`.`customer_id`
|
||||
ORDER BY `total_amount` DESC
|
||||
LIMIT 100
|
||||
-- 正确:聚合基于完整数据计算,LIMIT只限制最终返回结果的行数,且只出现在最外层查询
|
||||
</output-good>
|
||||
</example>
|
||||
</basic-examples>
|
||||
|
||||
example_engine: StarRocks 3.0
|
||||
|
||||
@@ -28,7 +28,7 @@ template:
|
||||
<step>1. 分析用户问题,确定查询需求</step>
|
||||
<step>2. 根据表结构生成基础SQL</step>
|
||||
<step>3. <strong>强制检查:逐字验证SQL中使用的表名和字段名是否在<m-schema>中定义,且字符必须完全匹配(包括繁简体、大小写、特殊字符),不得有任何转换。如发现任何不一致,必须重新生成SQL。</strong></step>
|
||||
<step>4. <strong>强制检查:应用数据量限制规则(默认限制或用户指定数量)</strong></step>
|
||||
<step>4. <strong>强制检查:应用数据量限制规则(默认限制或用户指定数量),限制必须位于最外层查询,不得出现在子查询、派生表、CTE内部</strong></step>
|
||||
<step>5. 应用其他规则(引号、别名、格式化等)</step>
|
||||
<step>6. <strong>强制检查:验证SQL语法是否符合<db-engine>规范</strong></step>
|
||||
<step>7. 确定图表类型(根据规则选择table/column/bar/line/pie)</step>
|
||||
@@ -41,17 +41,22 @@ template:
|
||||
<rule priority="critical" id="data-limit-policy">
|
||||
<title>数据量限制策略(必须严格遵守 - 零容忍)</title>
|
||||
<requirements>
|
||||
<requirement level="must-zero-tolerance">所有生成的SQL必须包含数据量限制,这是强制要求</requirement>
|
||||
<requirement level="must-zero-tolerance">每条生成的完整SQL语句,最外层查询必须包含数据量限制,这是强制要求</requirement>
|
||||
<requirement level="must">默认限制:1000条(除非用户明确指定其他数量,如"查询前10条")</requirement>
|
||||
<requirement level="must">当用户说"所有数据"或"全部数据"时,视为用户没有指定数量,使用默认的1000条限制</requirement>
|
||||
<requirement level="must">数据量限制只能应用在最外层查询上,限制的是最终返回结果的行数,而不是参与计算的数据量</requirement>
|
||||
<requirement level="must">禁止在子查询、派生表、CTE内部添加数据量限制,聚合、统计、排序等计算必须基于完整数据,否则会导致结果错误</requirement>
|
||||
<requirement level="must">忘记添加数据量限制是不可接受的错误</requirement>
|
||||
</requirements>
|
||||
|
||||
<enforcement>
|
||||
<action>如果生成的SQL没有数据量限制,必须重新生成</action>
|
||||
<action>在最终返回前必须验证限制是否存在</action>
|
||||
<action>不要因为用户说"所有数据"而拒绝生成SQL,只需自动加上1000条限制即可</action>
|
||||
<action>在最终返回前必须验证:数据量限制存在于最外层查询,且所有子查询内部均没有数据量限制</action>
|
||||
<action>不要因为用户说"所有数据"而拒绝生成SQL,只需在最外层自动加上1000条限制即可</action>
|
||||
</enforcement>
|
||||
<note>
|
||||
用户明确要求的"每组前N"类需求(如"每个部门薪资最高的前3名"),属于分组内的行数条件:若数据库引擎支持窗口函数,应通过ROW_NUMBER()等窗口函数配合WHERE条件实现;若引擎不支持窗口函数,则使用该引擎支持的等效写法实现。这类分组内的行数条件不视为违反本规则
|
||||
</note>
|
||||
</rule>
|
||||
no_query_limit: |
|
||||
<rule priority="critical" id="data-limit-policy">
|
||||
@@ -59,11 +64,15 @@ template:
|
||||
<requirements>
|
||||
<requirement>默认不限制数据量,返回全部数据(除非用户明确指定其他数量)</requirement>
|
||||
<requirement>不要臆测场景可能需要的数据量限制,以用户明确指定的数量为准</requirement>
|
||||
<requirement>用户明确说"前N条"、"限制N条"、"N条"等条件时,必须添加限制</requirement>
|
||||
<requirement>用户明确说"前N条"、"限制N条"、"N条"等条件时,必须添加限制,且该限制只能应用在最外层查询上,限制的是最终返回结果的行数</requirement>
|
||||
<requirement>禁止在子查询、派生表、CTE内部添加数据量限制,聚合、统计、排序等计算必须基于完整数据</requirement>
|
||||
</requirements>
|
||||
<enforcement>
|
||||
<action>不要拒绝查询所有数据的情况</action>
|
||||
</enforcement>
|
||||
<note>
|
||||
用户明确要求的"每组前N"类需求(如"每个部门薪资最高的前3名"),属于分组内的行数条件:若数据库引擎支持窗口函数,应通过ROW_NUMBER()等窗口函数配合WHERE条件实现;若引擎不支持窗口函数,则使用该引擎支持的等效写法实现。这类分组内的行数条件不视为在子查询内添加数据量限制
|
||||
</note>
|
||||
</rule>
|
||||
multi_table_condition: |
|
||||
<rule>
|
||||
|
||||
Reference in New Issue
Block a user