Course Content
Scenario-Based AI Engineering Questions
26 sections · 146 lessons
Your LLM-generated SQL works 95% of the time. The remaining 5% silently produces incorrect analytics dashboards. How do you validate and safely execute AI-generated database queries?
What you need to know
Why the 5% is silent
The common errors do not fail: they return numbers that look fine.
| Error | What happens |
|---|---|
| Join fan-out | Joining orders to order items repeats each order's total per item, so SUM(total) is too big |
| Wrong grain | A "per region" query returns one row per store |
| Missing filter | Cancelled or test orders are counted |
| Wrong definition | "Revenue" computed before discounts instead of after |
| Wrong date logic | A time zone or "last month" boundary shifts totals |
Validate before running
1import sqlglot2from sqlglot import exp34ALLOWED = {"orders_certified", "customers_certified", "regions"}56def validate(sql: str) -> str:7 tree = sqlglot.parse_one(sql, read="postgres")8 if not isinstance(tree, exp.Select):9 raise ValueError("only SELECT is allowed")10 tables = {t.name for t in tree.find_all(exp.Table)}11 if not tables <= ALLOWED:12 raise ValueError(f"unapproved tables: {tables - ALLOWED}")13 for join in tree.find_all(exp.Join):14 if not join.args.get("on") and not join.args.get("using"):15 raise ValueError("join without a condition (cartesian product)")16 where = tree.args.get("where")17 if where is None or "tenant_id" not in {c.name for c in where.find_all(exp.Column)}:18 raise ValueError("tenant filter missing")19 return tree.limit(10000).sql(dialect="postgres")The parser turns SQL into a tree, so checks are exact rather than regex guesses: only SELECT, only certified tables, no join without a condition, a required tenant filter, and a row limit added.
After running
- Execute safely — read-only role, replica, statement timeout, row cap.
- Check the result — row count against expectation, null rates, and grain: a per-region query must not return more rows than there are regions.
- Cross-check high-stakes queries — generate twice from different phrasings; if results differ, send to a human.
- Explain — show the SQL and its assumptions in plain English ("excludes cancelled orders; dates in IST").
- Promote for dashboards — an analyst reviews the query once, and it is saved and versioned.
A real-life example
Scenario, numbers made up. An e-commerce company's "ask your data" tool builds a monthly revenue dashboard. For three months, revenue is overstated by 18%, and a planning meeting uses the figure. The query joined orders to order_items and summed the order total, repeating it once per item.
The fix: the model now queries orders_certified, where net_revenue is defined once, and join paths come from the semantic layer. Parser validation blocks uncertified tables, and a grain check flags any result with more rows than the expected groups. Dashboard queries are saved after analyst review and are no longer regenerated on refresh. In an eval of 300 questions with known answers, silent wrong results fall from 5% to under 1%; most of the remainder now fail loudly instead.
Follow-up questions to expect
- "How do you evaluate text-to-SQL?" — Execution accuracy: run the generated and the reference query on the same data and compare result sets, over a set of real business questions.
- "Why not just give the model the full schema?" — Hundreds of tables with similar names invite wrong joins. A small set of certified views with descriptions is easier to use correctly.
- "What about write queries?" — Not from this tool. Analytics generation is read-only by role, not just by validation.