Introduction
AI assistants can generate SQL surprisingly quickly.
A developer can describe a requirement such as:
"Find the top five customers by total order value
during the previous month."and receive a complete query within seconds.
The difficult part is not generating SQL.
The difficult part is determining whether the generated SQL is correct, efficient, safe, and appropriate for the target database.
A query can return results and still contain a serious problem. It might use the wrong date range, duplicate rows because of an incorrect join, ignore an important filter, or perform an expensive table scan.
This makes AI-generated SQL a good candidate for systematic benchmarking.
Instead of asking which AI model "writes the best SQL," a more useful approach is to measure several independent dimensions:
Semantic correctness
Result correctness
Query-plan quality
Execution behavior
Resource consumption
Safety
Database cost
This article presents a vendor-neutral methodology for building such a benchmark.
Why AI-Generated SQL Needs Testing
Consider a simple schema:
CREATE TABLE customers
(
id bigint PRIMARY KEY,
name varchar(200) NOT NULL
);
CREATE TABLE orders
(
id bigint PRIMARY KEY,
customer_id bigint NOT NULL,
order_date date NOT NULL,
total numeric(12, 2) NOT NULL,
CONSTRAINT fk_orders_customers
FOREIGN KEY (customer_id)
REFERENCES customers(id)
);An AI assistant might generate:
SELECT c.name, SUM(o.total) AS total_sales
FROM customers c
JOIN orders o
ON c.id = o.customer_id
GROUP BY c.name
ORDER BY total_sales DESC
LIMIT 5;The query is syntactically valid.
But suppose the requirement was:
Return the top five customers by order value during the previous month.
The generated query does not contain a date filter.
It can execute successfully while producing the wrong business result.
This is why:
SQL executes successfully
!=
SQL is correctDefine What Correctness Means
Before comparing AI-generated SQL, define the expected behavior.
A useful evaluation model is:
AI-Generated SQL
|
+--> Syntax Correct?
|
+--> Schema Correct?
|
+--> Result Correct?
|
+--> Business Logic Correct?
|
+--> Safe?
|
+--> Efficient?Each category should be evaluated separately.
Build a Benchmark Schema
Create a controlled database schema that resembles real application workloads.
Include relationships such as:
Customers
|
+---- Orders
|
+---- OrderItems
|
+---- ProductsYou can also include:
One-to-many relationships
Many-to-many relationships
Nullable columns
Date and timestamp fields
Numeric values
JSON columns
Indexes
Constraints
The goal is to create realistic SQL problems without exposing production data.
Create Representative Questions
The benchmark should contain natural-language requirements rather than only SQL syntax exercises.
For example:
Find all customers who placed at least
three orders in the previous 30 days.Another:
Return the five products with the highest
revenue during the current quarter.And:
Find customers who have never placed an order.These questions test different SQL concepts.
Organize Tests by Difficulty
A useful benchmark can have several levels.
| Level | Example |
|---|---|
| Basic | Filter rows by a condition |
| Intermediate | Join multiple tables |
| Advanced | Aggregation and grouping |
| Complex | CTEs and window functions |
| Production-like | Multiple joins, filters, and business rules |
This makes the results easier to interpret.
Establish Ground-Truth Queries
Each natural-language requirement needs a trusted reference query.
For example:
SELECT
c.id,
c.name,
SUM(o.total) AS total_sales
FROM customers AS c
JOIN orders AS o
ON o.customer_id = c.id
WHERE o.order_date >= DATE '2026-07-01'
AND o.order_date < DATE '2026-08-01'
GROUP BY
c.id,
c.name
ORDER BY
total_sales DESC
LIMIT 5;The benchmark should treat this as a reference implementation, not necessarily as the only valid SQL solution.
Two queries can be structurally different and still be equally correct.
Why Result-Based Validation Is Better
Suppose the AI generates:
SELECT
c.id,
c.name,
SUM(o.total) AS total_sales
FROM orders o
JOIN customers c
ON c.id = o.customer_id
WHERE o.order_date >= DATE '2026-07-01'
AND o.order_date < DATE '2026-08-01'
GROUP BY c.id, c.name
ORDER BY total_sales DESC
LIMIT 5;The structure is different from the reference query, but the result can still be correct.
Therefore, compare result sets where possible.
Conceptually:
Reference Query
|
v
Expected Result
|
+----------------+
|
AI Query |
| |
v |
Actual Result ---------+
|
v
CompareThis is more useful than comparing SQL strings.
Testing With a Controlled Dataset
Create deterministic test data.
For example:
INSERT INTO customers (id, name)
VALUES
(1, 'Alice'),
(2, 'Bob'),
(3, 'Charlie');
INSERT INTO orders
(id, customer_id, order_date, total)
VALUES
(101, 1, DATE '2026-07-05', 500),
(102, 1, DATE '2026-07-10', 300),
(103, 2, DATE '2026-07-12', 900),
(104, 3, DATE '2026-06-20', 1200);Now the benchmark knows exactly what the correct result should be.
Use multiple datasets when necessary to expose edge cases.
Testing Edge Cases
A good SQL benchmark should include cases such as:
No matching rows
Duplicate values
NULL values
Customers without orders
Orders without optional values
Multiple rows with the same total
Boundary dates
Empty tables
Very large values
For example, a question about customers without orders should expose incorrect use of an inner join.
Correct:
SELECT c.id, c.name
FROM customers AS c
LEFT JOIN orders AS o
ON o.customer_id = c.id
WHERE o.id IS NULL;An AI-generated inner join could silently return the wrong result.
Testing Date Logic
Date filtering is a common source of subtle SQL errors.
For example:
WHERE order_date
BETWEEN '2026-07-01' AND '2026-07-31'may behave differently from an explicit half-open interval when the column contains timestamps.
A safer pattern for timestamps is often:
WHERE created_at >= TIMESTAMP '2026-07-01 00:00:00'
AND created_at < TIMESTAMP '2026-08-01 00:00:00'The benchmark should include boundary cases.
For example:
2026-07-31 23:59:59
2026-08-01 00:00:00This can reveal whether the generated query handles the requested time period correctly.
Testing NULL Behavior
AI-generated SQL can also mishandle NULL values.
Consider:
SELECT *
FROM customers
WHERE email <> '[email protected]';Rows where email is NULL do not satisfy the comparison in the same way as ordinary values.
Benchmark questions should include NULL-heavy datasets when the business logic requires them.
Measuring Query Correctness
Create a result-comparison layer.
For example, conceptually:
bool ResultsMatch(
IReadOnlyList<Row> expected,
IReadOnlyList<Row> actual)
{
return Normalize(expected)
.SequenceEqual(Normalize(actual));
}The normalization step may need to account for:
Row ordering
Numeric precision
Date formatting
Column ordering
Only normalize differences that are semantically irrelevant.
If ordering is part of the requirement, preserve it during comparison.
Testing Query Plans
A correct query can still be inefficient.
Use the database's execution-plan tooling to inspect generated SQL.
For PostgreSQL, for example:
EXPLAIN (ANALYZE, BUFFERS)
SELECT
c.id,
c.name,
SUM(o.total) AS total_sales
FROM customers AS c
JOIN orders AS o
ON o.customer_id = c.id
GROUP BY c.id, c.name;For SQL Server, equivalent execution-plan and statistics features can be used.
The benchmark should use the tools appropriate for the target database.
What to Measure in a Query Plan
Useful metrics include:
Join the conversation! Your thoughts help the community grow.