← Blog

How to Build a Claude-Powered SQL Query Generator

2026-11-03 · 5 min read · SubToAPI Team

What a Claude-Powered SQL Query Generator Actually Does

A Claude-powered SQL query generator takes a plain-English question like "show me top 10 customers by revenue last quarter" and turns it into a working SQL statement against your actual database schema. You build it by feeding Claude your table structure, asking it to produce SQL (not prose), validating the output, and running it through a read-only or sandboxed connection before it ever touches production data.

This is a well-suited task for an LLM because SQL generation is fundamentally a translation problem — natural language in, structured query out — and Claude is strong at following schema constraints when you give it enough context. The hard part isn't getting Claude to write SQL; it's making sure the SQL is correct, safe, and doesn't guess at column names that don't exist. Below is a practical architecture you can implement today.

Step 1: Ground Claude in Your Schema

Never ask Claude to generate SQL without giving it the schema. Pull your table and column names, types, and relationships, and pass them as context in every request.

-- Example schema snippet you'd send as context
CREATE TABLE customers (
  id INT PRIMARY KEY,
  name TEXT,
  signup_date DATE,
  plan TEXT
);

CREATE TABLE orders (
  id INT PRIMARY KEY,
  customer_id INT REFERENCES customers(id),
  amount DECIMAL,
  created_at TIMESTAMP
);

For larger databases, don't dump the entire schema on every call — it wastes tokens and increases hallucination risk. Instead, do a lightweight retrieval step first: match the user's question against table/column names (simple keyword matching is often enough) and only include the relevant tables in the prompt.

Step 2: Write a Tight System Prompt

The system prompt should specify the SQL dialect, forbid destructive statements, and force Claude to return only SQL — no explanations mixed in unless you ask for them separately.

You are a SQL generator for PostgreSQL. You will be given a database
schema and a natural language question. Return ONLY a single valid
SQL SELECT statement that answers the question. Rules:
- Never generate INSERT, UPDATE, DELETE, DROP, ALTER, or TRUNCATE statements.
- Only reference tables and columns that exist in the provided schema.
- If the question cannot be answered with the given schema, return exactly: UNANSWERABLE
- Use explicit JOINs, never implicit comma joins.

This kind of constraint-heavy prompt is the single biggest lever for output quality — more effective than fancier prompting tricks.

Step 3: Call the API with Schema + Question

Here's a minimal example using SubToAPI, which exposes Claude as a plain HTTPS endpoint with an application API key, so you don't need to manage Anthropic credentials directly in your backend:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4",
    "max_tokens": 300,
    "system": "You are a SQL generator for PostgreSQL. Return ONLY SQL, no markdown fences.",
    "messages": [
      {
        "role": "user",
        "content": "Schema:\nCREATE TABLE customers (id INT, name TEXT, plan TEXT);\nCREATE TABLE orders (id INT, customer_id INT, amount DECIMAL, created_at TIMESTAMP);\n\nQuestion: What is total revenue per plan in the last 30 days?"
      }
    ]
  }'

The response comes back as structured JSON with the generated text in a predictable place, which makes it easy to extract the SQL string programmatically. See the messages docs for the exact response shape.

Step 4: Validate Before Execution

Treat every generated query as untrusted input, even though it came from your own LLM call. A solid validation layer includes:

function isSafeQuery(sql) {
  const normalized = sql.trim().toUpperCase();
  if (!normalized.startsWith("SELECT")) return false;
  const forbidden = ["DROP", "DELETE", "UPDATE", "INSERT", "ALTER", "TRUNCATE", ";--"];
  return !forbidden.some(word => normalized.includes(word));
}

This is a basic check, not a full defense — pair it with a proper SQL parser and the read-only DB role for anything user-facing.

Step 5: Stream Results for Better UX

If you're building this into a dashboard or chat interface, streaming the SQL generation step feels more responsive than waiting for the full response, especially for complex multi-table queries where Claude's reasoning takes a few seconds. SubToAPI supports streaming responses over the same endpoint — see streaming docs for the event format.

Step 6: Handle Ambiguity and Errors Gracefully

Real users ask vague questions. "Show me our best customers" doesn't define "best." Two practical patterns:

  1. Clarifying follow-up: if Claude returns UNANSWERABLE or a low-confidence query, have it ask a clarifying question instead of guessing.
  2. Explain-then-confirm: ask Claude to return both the SQL and a one-sentence plain-English explanation of what it computed, and show that explanation to the user before running the query. This catches misinterpretations before they produce a wrong (but syntactically valid) result.

Step 7: Add Tool Use for Multi-Step Workflows

For more advanced generators — ones that need to check row counts first, or look up a customer ID before writing the main query — Claude's tool use feature lets the model call intermediate functions (like list_tables or get_sample_rows) before finalizing the SQL. This turns a one-shot generator into an agent that explores the schema the way a human analyst would. SubToAPI supports tool calling through the same API; see the tool use docs for the request/response format.

Getting Started

If you want to prototype this quickly: sign up for a free trial, check the quickstart guide, and wire up the schema-grounding and validation layers described above. Pricing starts at the Solo plan (€9/month) for individual projects, scaling to Team and Scale plans with per-seat billing for larger engineering teams — see pricing for details.

FAQ

Can Claude generate SQL without seeing my schema? Technically yes, but it will hallucinate column and table names. Always pass the relevant schema in context — it's the single biggest factor in output accuracy.

Is it safe to let Claude's SQL run directly against my production database? Not without safeguards. Use a read-only database role, validate the statement type, parse it against your actual schema, and enforce row/time limits before execution.

What's the best way to handle complex multi-table questions? Break the schema retrieval into a smaller, relevant subset, and consider using tool use so Claude can inspect tables or sample data before generating the final query.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →