Spaces:
Running
Running
Commit Β·
4791304
1
Parent(s): c442c5a
added join status logic
Browse files- ai/signatures.py +19 -1
- ai/sql_pattern_checker.py +52 -0
ai/signatures.py
CHANGED
|
@@ -270,6 +270,15 @@ class AnalyzeAndPlan(dspy.Signature):
|
|
| 270 |
β’ Component cost queries from sales_order_line_pricing
|
| 271 |
(join back to sales_order and apply status = 'closed')
|
| 272 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 273 |
NEVER apply status = 'closed' to:
|
| 274 |
β’ Purchase order tables (they have a separate status column)
|
| 275 |
β’ Inventory tables
|
|
@@ -490,7 +499,16 @@ class SQLGeneration(dspy.Signature):
|
|
| 490 |
- NEVER add gold_amount + diamond_amount or any component columns β
|
| 491 |
that always gives the WRONG answer (misses labour, taxes, etc.)
|
| 492 |
|
| 493 |
-
6. STATUS = 'closed' IS THE DEFAULT
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 494 |
Unless the question explicitly mentions a different status (e.g. "pending",
|
| 495 |
"open", "cancelled", "all orders"), ALWAYS add WHERE so.status = 'closed'.
|
| 496 |
This is not optional β omitting it returns incomplete/incorrect data.
|
|
|
|
| 270 |
β’ Component cost queries from sales_order_line_pricing
|
| 271 |
(join back to sales_order and apply status = 'closed')
|
| 272 |
|
| 273 |
+
IMPORTANT β line-level tables have NO status column:
|
| 274 |
+
sales_order_line_pricing, sales_order_line_gold, sales_order_line_diamond,
|
| 275 |
+
and sales_order_line do NOT have a status column.
|
| 276 |
+
To apply the status filter when using these tables, you MUST join back to
|
| 277 |
+
sales_table_v2_sales_order and filter on so.status = 'closed':
|
| 278 |
+
JOIN sales_table_v2_sales_order_line sol ON lp.sol_id = sol.sol_id
|
| 279 |
+
JOIN sales_table_v2_sales_order so ON sol.so_id = so.so_id
|
| 280 |
+
WHERE so.status = 'closed'
|
| 281 |
+
|
| 282 |
NEVER apply status = 'closed' to:
|
| 283 |
β’ Purchase order tables (they have a separate status column)
|
| 284 |
β’ Inventory tables
|
|
|
|
| 499 |
- NEVER add gold_amount + diamond_amount or any component columns β
|
| 500 |
that always gives the WRONG answer (misses labour, taxes, etc.)
|
| 501 |
|
| 502 |
+
6. STATUS = 'closed' IS THE DEFAULT β AND LINE TABLES HAVE NO STATUS COLUMN:
|
| 503 |
+
sales_order_line_pricing / sales_order_line_gold / sales_order_line_diamond
|
| 504 |
+
do NOT have a status column. When using these tables, you MUST join back to
|
| 505 |
+
sales_table_v2_sales_order to apply the filter:
|
| 506 |
+
JOIN sales_table_v2_sales_order_line sol ON lp.sol_id = sol.sol_id
|
| 507 |
+
JOIN sales_table_v2_sales_order so ON sol.so_id = so.so_id
|
| 508 |
+
WHERE so.status = 'closed'
|
| 509 |
+
Omitting this join means ALL orders (cancelled, pending, open) are included β WRONG.
|
| 510 |
+
|
| 511 |
+
6b. STATUS = 'closed' IS THE DEFAULT FOR ALL SALES ORDER QUERIES:
|
| 512 |
Unless the question explicitly mentions a different status (e.g. "pending",
|
| 513 |
"open", "cancelled", "all orders"), ALWAYS add WHERE so.status = 'closed'.
|
| 514 |
This is not optional β omitting it returns incomplete/incorrect data.
|
ai/sql_pattern_checker.py
CHANGED
|
@@ -237,6 +237,58 @@ def check_sql_patterns(sql: str) -> list[dict[str, Any]]:
|
|
| 237 |
# Generic β works for gold_kt on pricing table, or any future similar mistake.
|
| 238 |
issues.extend(check_column_table_mismatches(sql))
|
| 239 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 240 |
return issues
|
| 241 |
|
| 242 |
|
|
|
|
| 237 |
# Generic β works for gold_kt on pricing table, or any future similar mistake.
|
| 238 |
issues.extend(check_column_table_mismatches(sql))
|
| 239 |
|
| 240 |
+
# ββ Pattern 5 ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 241 |
+
# Sales line tables used without joining sales_order for the status filter.
|
| 242 |
+
# Any query on line-level tables (pricing, gold, diamond, sales_order_line)
|
| 243 |
+
# must join back to sales_table_v2_sales_order and apply status = 'closed'
|
| 244 |
+
# unless a different status is explicitly present in the SQL.
|
| 245 |
+
SALES_LINE_TABLES = {
|
| 246 |
+
"sales_table_v2_sales_order_line_pricing",
|
| 247 |
+
"sales_table_v2_sales_order_line_gold",
|
| 248 |
+
"sales_table_v2_sales_order_line_diamond",
|
| 249 |
+
"sales_table_v2_sales_order_line",
|
| 250 |
+
}
|
| 251 |
+
SALES_HEADER = "sales_table_v2_sales_order"
|
| 252 |
+
|
| 253 |
+
tables_in_sql = {t.lower() for t in re.findall(r'\b(\w+)\b', sql_lower)}
|
| 254 |
+
uses_line_table = bool(SALES_LINE_TABLES & tables_in_sql)
|
| 255 |
+
has_sales_header = SALES_HEADER in tables_in_sql
|
| 256 |
+
has_status_filter = bool(re.search(r"\bstatus\s*=", sql_lower))
|
| 257 |
+
|
| 258 |
+
if uses_line_table and not has_status_filter:
|
| 259 |
+
# Only flag if the header table is absent (status can't be filtered)
|
| 260 |
+
# OR if the header is present but status filter is still missing
|
| 261 |
+
issues.append({
|
| 262 |
+
"pattern_name": "missing_status_closed_on_line_tables",
|
| 263 |
+
"description": (
|
| 264 |
+
"MISSING status = 'closed' filter: the query uses sales line tables "
|
| 265 |
+
"(sales_order_line_pricing / sales_order_line_gold / sales_order_line_diamond) "
|
| 266 |
+
"but does not filter by sales_order status. "
|
| 267 |
+
"Line tables have no status column β you must JOIN sales_table_v2_sales_order "
|
| 268 |
+
"and add WHERE so.status = 'closed' to exclude incomplete/cancelled orders."
|
| 269 |
+
),
|
| 270 |
+
"correction": (
|
| 271 |
+
"Add a JOIN to sales_table_v2_sales_order and filter by status:\n"
|
| 272 |
+
"\n"
|
| 273 |
+
"JOIN sales_table_v2_sales_order_line sol ON lp.sol_id = sol.sol_id\n"
|
| 274 |
+
"JOIN sales_table_v2_sales_order so ON sol.so_id = so.so_id\n"
|
| 275 |
+
"WHERE so.status = 'closed'\n"
|
| 276 |
+
"\n"
|
| 277 |
+
"Full corrected structure example:\n"
|
| 278 |
+
"SELECT g.gold_kt,\n"
|
| 279 |
+
" SUM(lp.gold_amount_per_unit * lp.quantity) AS total_gold_amount,\n"
|
| 280 |
+
" SUM(lp.diamond_amount_per_unit * lp.quantity) AS total_diamond_amount,\n"
|
| 281 |
+
" SUM(lp.making_charges_per_unit * lp.quantity) AS total_making_charges\n"
|
| 282 |
+
"FROM sales_table_v2_sales_order_line_pricing lp\n"
|
| 283 |
+
"JOIN sales_table_v2_sales_order_line_gold g ON lp.sol_id = g.sol_id\n"
|
| 284 |
+
"JOIN sales_table_v2_sales_order_line sol ON lp.sol_id = sol.sol_id\n"
|
| 285 |
+
"JOIN sales_table_v2_sales_order so ON sol.so_id = so.so_id\n"
|
| 286 |
+
"WHERE so.status = 'closed'\n"
|
| 287 |
+
"GROUP BY g.gold_kt\n"
|
| 288 |
+
"ORDER BY g.gold_kt"
|
| 289 |
+
),
|
| 290 |
+
})
|
| 291 |
+
|
| 292 |
return issues
|
| 293 |
|
| 294 |
|