How to Write SQL Using AI
Use an AI assistant to write SQL queries you can trust. Give it your table structure, ask a clear question, then check the answer on a small sample you can count by hand.
In short: paste the CREATE TABLE lines (not real data), name your database (PostgreSQL, MySQL, SQLite, SQL Server), state the question, and test on a tiny sample with a known answer.
Why SQL with AI
Almost every company stores data in SQL databases: banks, e-commerce, hospitals. Analysts and developers write queries daily. AI writes them fast, but a wrong JOIN or date filter gives wrong numbers that look right.
What you need
- The schema: the CREATE TABLE statements: table names, columns, types, keys.
- Your database name and version: SQL differs a little between PostgreSQL, MySQL, SQLite and SQL Server.
- A small sample: a few rows where you know the right answer.
- A safe place to run it: a local copy or test database, never production first.
How it flows
Set up a safe practice database
- Python already includes SQLite. No install needed.
- Or install PostgreSQL / MySQL locally, or use a Docker container.
- Create the sample tables below and load the 5 rows.
CREATE TABLE customers (id INTEGER PRIMARY KEY, name TEXT NOT NULL, city TEXT NOT NULL); CREATE TABLE orders ( id INTEGER PRIMARY KEY, customer_id INTEGER NOT NULL REFERENCES customers(id), amount NUMERIC(10,2) NOT NULL, created_at DATE NOT NULL ); INSERT INTO customers VALUES (1,'Asha','Pune'),(2,'Ravi','Mumbai'),(3,'Meena','Nagpur'); INSERT INTO orders VALUES (1,1,1200.00,'2026-01-15'),(2,1,800.00,'2026-03-02'),(3,2,5000.00,'2026-02-20'), (4,3,300.00,'2025-12-30'),(5,2,700.00,'2026-07-01');
Step 1 — the prompt
PostgreSQL. Tables: customers(id, name, city) and orders(id, customer_id, amount, created_at DATE). Write a query that shows each customer's name, city, number of orders and total amount for orders in 2026 only, highest total first. Use a date range that can use an index (no functions on the column). Only return the SQL.
Step 2 — the query (tested here)
top_customers.sql-- Total spend per customer in 2026, highest first. Built with an AI assistant, then tested.
SELECT c.name,
c.city,
COUNT(o.id) AS orders,
SUM(o.amount) AS total
FROM customers AS c
JOIN orders AS o ON o.customer_id = c.id
WHERE o.created_at >= '2026-01-01'
AND o.created_at < '2027-01-01'
GROUP BY c.id, c.name, c.city
ORDER BY total DESC;# expected on the sample (count by hand first):
# Ravi Mumbai 2 5700 (5000 + 700)
# Asha Pune 2 2000 (1200 + 800)
# Meena is not listed: her only order is in 2025Step 3 — run queries from code safely
Ask: “Show me how to run this from Python with a parameter for the city, no string joining.”
safe_query.py"""Run a query safely with a parameter (no string joining). Tested with SQLite."""
import sqlite3
def orders_for_city(conn, city):
sql = """SELECT o.id, o.amount FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE c.city = ? ORDER BY o.id"""
return conn.execute(sql, (city,)).fetchall()test_sql.pyimport sqlite3
from safe_query import orders_for_city
def db():
conn = sqlite3.connect(":memory:")
conn.executescript(open("schema.sql").read())
return conn
def test_top_customers_2026():
rows = db().execute(open("top_customers.sql").read()).fetchall()
assert rows == [("Ravi", "Mumbai", 2, 5700), ("Asha", "Pune", 2, 2000)] # Meena's order is 2025
def test_parameter_blocks_injection():
conn = db()
assert orders_for_city(conn, "Pune") == [(1, 1200), (2, 800)]
assert orders_for_city(conn, "Pune' OR '1'='1") == []pytest -q
# -> 2 passedThe second test passes an attack string as the city. Because of the ? parameter, it is treated as plain text and returns nothing.
How to check any AI query
- Count by hand on 5–10 rows first.
- Check every JOIN: INNER JOIN drops rows with no match; LEFT JOIN keeps them.
- Check date ranges: use
>= start AND < next_start; avoidBETWEENwith timestamps. - Check GROUP BY includes every non-aggregated column.
- Look at the plan:
EXPLAIN(PostgreSQL/MySQL) before running on big tables. - Run as a read-only user when exploring real data.
Watch out (common AI mistakes in SQL)
- Wrong database dialect —
LIMITvsTOP, date functions differ; always name your DB. - Functions on indexed columns (
YEAR(created_at) = 2026) — slow on big tables. - String-joined SQL in code — SQL injection risk; use parameters.
- UPDATE or DELETE without WHERE — always run a SELECT with the same WHERE first, inside a transaction.
Quick quiz
1. What should you give the AI instead of real data?
The CREATE TABLE schema and a few fake sample rows.
2. Why was Meena missing from the result?
Her only order was in 2025, outside the 2026 range.
3. What stops SQL injection in code?
Query parameters (like ? or %s), never string joining.
4. Safer date filter than YEAR(created_at) = 2026?
created_at >= '2026-01-01' AND created_at < '2027-01-01'.
Save tokens and money
Paste only the tables the query needs, not the whole database schema. Ask for the query only, without long explanations. Reuse a working prompt as a template for similar reports.