DEV Community

Vivek Kumar
Vivek Kumar

Posted on

When to Trust AI-Generated SQL (And When Not To)

You paste "show me monthly revenue by plan for the last year" into an AI assistant, and three seconds later you have a 20-line query with a CTE, a date filter, and a GROUP BY. It runs. It returns numbers. The numbers look reasonable.

So you ship it.

That last step is where things go wrong. AI is genuinely good at writing SQL now — good enough that the real skill is no longer "can it write the query" but "should I trust this query." Because AI-generated SQL doesn't fail like a compiler error that screams at you. It fails silently, returning a perfectly plausible result that happens to be wrong.

This article isn't a validation checklist you run on every query. It's a mental model for triage: which AI-generated queries are safe to trust at a glance, which need a second look, and which you should never ship without understanding line by line.

The core problem: SQL fails quietly

When AI hallucinates a Python function name, you get an error. When AI hallucinates SQL logic, you get a number. A revenue column that's silently doubled looks identical to correct revenue — until finance asks why the dashboard disagrees with the accounting system.

There was a widely-cited finding that developers shipping AI-generated code without review introduced markedly more security and correctness issues than those who reviewed it first. The lesson isn't "don't use AI." It's that the output looks finished, which makes it easy to skip the review that the code still needs.

So instead of trusting or distrusting AI wholesale, sort queries by how catastrophically they can fail quietly.

The trust spectrum

Here's the framework I use. Every AI-generated query falls into one of three zones based on structure, not vibes.

Zone Query shape How to treat it
Green — trust Single table, simple filters and aggregates Skim and ship
Yellow — verify Joins, subqueries, date logic, window functions Read carefully, spot-check output
Red — scrutinize Multi-table joins with aggregates, anything that writes data, anything touching money or auth Understand every line before running

Let's walk through each.

Green zone: trust it

Single-table queries with straightforward filtering and aggregation are the sweet spot for AI. These patterns are everywhere in training data, and there's almost nowhere for the logic to hide a mistake.

-- "How many users signed up last month?"
SELECT COUNT(*)
FROM users
WHERE created_at >= '2026-06-01'
  AND created_at <  '2026-07-01';
Enter fullscreen mode Exit fullscreen mode
-- "Total revenue by plan"
SELECT plan, SUM(amount) AS total_revenue
FROM subscriptions
GROUP BY plan
ORDER BY total_revenue DESC;
Enter fullscreen mode Exit fullscreen mode

The only thing that can really go wrong here is the AI picking the wrong column (created_at vs signed_up_at) or a fuzzy date boundary. A glance at the column names and the date range is enough. Ship it.

Yellow zone: verify before you trust

The moment a query adds a join, a subquery, or window logic, the surface area for silent error grows. The query will still run. The result will still look fine. But now you need to actually read it.

Take date-bucketing, a place AI often gets almost right:

-- "Weekly active users for Q2"
SELECT date_trunc('week', event_time) AS week,
       COUNT(DISTINCT user_id) AS wau
FROM events
WHERE event_time >= '2026-04-01'
  AND event_time <  '2026-07-01'
GROUP BY 1
ORDER BY 1;
Enter fullscreen mode Exit fullscreen mode

This is correct — but notice the DISTINCT. Ask for "weekly active users" and some models will hand you COUNT(*), which counts events, not users. Both return a tidy number per week. Only one answers the question you asked. The tell isn't in whether it runs; it's in whether the aggregate matches the metric's definition.

For yellow-zone queries, the fastest verification is a spot check against a number you already trust. If your admin panel says 1,240 signups last week and the query says 1,240, the shape is probably right.

Red zone: never trust blindly

Multi-table joins that feed an aggregate are the single most dangerous thing AI writes, because of fan-out. When you join a table to another that has a one-to-many relationship, rows multiply — and any SUM or COUNT on top of that join silently inflates.

-- "Total revenue by customer"  -- looks fine, is wrong
SELECT c.name, SUM(o.amount) AS revenue
FROM customers c
JOIN orders       o  ON o.customer_id = c.id
JOIN order_items  oi ON oi.order_id   = o.id
GROUP BY c.name;
Enter fullscreen mode Exit fullscreen mode

Spot the bug: joining order_items multiplies each order row by its number of line items, so SUM(o.amount) counts each order's amount once per item. An order of $100 with 3 items now contributes $300. The total looks like healthy revenue growth. It's an artifact of the join.

The fix is to aggregate at the right grain — don't join a table you're not aggregating from:

SELECT c.name, SUM(o.amount) AS revenue
FROM customers c
JOIN orders o ON o.customer_id = c.id
GROUP BY c.name;
Enter fullscreen mode Exit fullscreen mode

The detection trick that catches almost every fan-out: check row counts before aggregating. If you have 50,000 orders and the pre-aggregation join returns 200,000 rows, something is multiplying your data.

-- run this first, before trusting any aggregate over a join
SELECT COUNT(*)
FROM customers c
JOIN orders       o  ON o.customer_id = c.id
JOIN order_items  oi ON oi.order_id   = o.id;
-- 200k rows for 50k orders? your SUM is inflated 4x.
Enter fullscreen mode Exit fullscreen mode

Also firmly in the red zone: anything with UPDATE, DELETE, or INSERT, and anything gating access by tenant or user. An AI-written DELETE FROM sessions WHERE ... with a subtly wrong WHERE clause doesn't return a wrong number — it removes the wrong rows, permanently. Never run AI-generated write statements without reading them, and wrap them in a transaction so you can ROLLBACK.

Common gotchas that cut across zones

A few silent-failure patterns show up regardless of query complexity, worth keeping in your head:

INNER JOIN where you needed LEFT JOIN. Ask for "all users and their order counts" and an inner join quietly drops every user with zero orders — exactly the users you might care about. Your "total users" shrinks and nobody notices.

Schema hallucination. The model invents a plausible column (users.last_login) that doesn't exist, or pulls the right column from the wrong table. Syntax errors here are the good case — you catch them. The bad case is a real column that means something different than you assumed.

NULLs in aggregates and filters. WHERE status != 'cancelled' silently excludes rows where status IS NULL, because NULL != 'cancelled' is not true. AI rarely accounts for this unless prompted.

Timezone and boundary drift. >= '2026-06-01' behaves differently depending on whether the column is a date, a naive timestamp, or a timestamptz. AI can't see your session timezone, so it guesses.

How to make AI-generated SQL more trustworthy

You can move queries toward the green zone by how you prompt and where you run them:

  • Give the AI your real schema. Column names, types, and relationships eliminate most hallucination and grain mistakes.
  • State the grain explicitly. "Revenue per customer, one row per customer" is much harder to get wrong than "revenue by customer."
  • Ask it to explain its joins. If the model can't justify why a join won't fan out, that's your signal to scrutinize.
  • Run reads against a replica or a read-only role. Trust is cheaper when a wrong query can't cost you anything.

Key takeaways

AI writes SQL fast, but speed is not correctness. Sort every query by blast radius: single-table aggregates are safe to skim; joins, subqueries, and window functions deserve a careful read and a spot check; multi-table aggregates, writes, and anything touching money or access control demand full understanding before you run them. The killer failure mode is fan-out inflating aggregates — check pre-aggregation row counts and you'll catch most of it. Treat AI as a fast first draft of the query, never the final answer, and keep your own understanding of the data model as the thing you actually trust.

Your turn

What's the worst silently-wrong query AI has handed you — a doubled revenue number, a dropped cohort, a DELETE that went too far? Drop it in the comments. And if you're building dashboards or reporting on top of your database, tools like Draxlr let you generate SQL with AI and keep a human in the loop with visual query building and row counts you can sanity-check before anything ships.

Top comments (0)