Skip to content
Learn Agentic AI
Learn Agentic AI12 min read4 views

Text-to-SQL with Claude: Using Anthropic's API for Database Question Answering

Implement a text-to-SQL system using Anthropic's Claude API with tool use for SQL execution, multi-turn conversations, and structured output parsing for reliable database question answering.

Why Claude for Text-to-SQL?

Claude excels at text-to-SQL for several reasons: its large context window handles massive schemas without truncation, its tool use feature enables agentic SQL execution loops, and its instruction-following precision reduces the need for complex prompt engineering. Claude also tends to be conservative — it asks for clarification rather than guessing, which is exactly what you want when generating database queries.

Setting Up the Anthropic Client

import anthropic
import sqlite3
from typing import Any

client = anthropic.Anthropic()  # Uses ANTHROPIC_API_KEY env var

def get_schema(db_path: str) -> str:
    conn = sqlite3.connect(db_path)
    cursor = conn.execute(
        "SELECT sql FROM sqlite_master WHERE type='table' AND sql IS NOT NULL"
    )
    schema = "\n\n".join(row[0] for row in cursor.fetchall())
    conn.close()
    return schema

def execute_query(db_path: str, sql: str) -> list[dict]:
    conn = sqlite3.connect(db_path)
    conn.row_factory = sqlite3.Row
    cursor = conn.execute(sql)
    results = [dict(row) for row in cursor.fetchall()]
    conn.close()
    return results

Using Claude's Tool Use for SQL Execution

Claude's tool use feature lets the model decide when to execute a SQL query and inspect the results. This is more powerful than a single-shot prompt because Claude can run a query, check the output, and refine it.

flowchart TD
    START["Text-to-SQL with Claude: Using Anthropic's API fo…"] --> A
    A["Why Claude for Text-to-SQL?"]
    A --> B
    B["Setting Up the Anthropic Client"]
    B --> C
    C["Using Claude39s Tool Use for SQL Execut…"]
    C --> D
    D["The Multi-Turn Conversation Loop"]
    D --> E
    E["Handling Multi-Step Questions"]
    E --> F
    F["Adding Guardrails"]
    F --> G
    G["FAQ"]
    G --> DONE["Key Takeaways"]
    style START fill:#4f46e5,stroke:#4338ca,color:#fff
    style DONE fill:#059669,stroke:#047857,color:#fff
tools = [
    {
        "name": "execute_sql",
        "description": "Execute a SQL query against the database and return results. "
                       "Use this to answer questions about the data.",
        "input_schema": {
            "type": "object",
            "properties": {
                "sql": {
                    "type": "string",
                    "description": "The SQL query to execute. Must be a SELECT statement.",
                },
                "reasoning": {
                    "type": "string",
                    "description": "Brief explanation of why this query answers the question.",
                },
            },
            "required": ["sql", "reasoning"],
        },
    }
]

SYSTEM_PROMPT = """You are a database analyst. You answer questions about data
by writing and executing SQL queries.

Database schema:
{schema}

Rules:
- Only use SELECT statements
- Always include LIMIT 100 unless the user asks for all results
- Use the execute_sql tool to run queries
- After seeing results, provide a natural language summary
- If a query fails, analyze the error and try a corrected version"""

The Multi-Turn Conversation Loop

The key pattern with Claude's tool use is a message loop: send the question, check if Claude wants to use a tool, execute the tool, feed the result back, and repeat until Claude provides a final text response.

def ask_database(question: str, db_path: str) -> str:
    schema = get_schema(db_path)
    messages = [{"role": "user", "content": question}]

    while True:
        response = client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=4096,
            system=SYSTEM_PROMPT.format(schema=schema),
            tools=tools,
            messages=messages,
        )

        # Check if Claude wants to use a tool
        if response.stop_reason == "tool_use":
            # Extract tool use block
            tool_block = next(
                b for b in response.content if b.type == "tool_use"
            )
            sql = tool_block.input["sql"]

            # Execute the query safely
            try:
                results = execute_query(db_path, sql)
                tool_result = {
                    "type": "tool_result",
                    "tool_use_id": tool_block.id,
                    "content": str(results[:50]),  # Cap result size
                }
            except Exception as e:
                tool_result = {
                    "type": "tool_result",
                    "tool_use_id": tool_block.id,
                    "content": f"Error: {str(e)}",
                    "is_error": True,
                }

            # Add assistant response and tool result to conversation
            messages.append({"role": "assistant", "content": response.content})
            messages.append({"role": "user", "content": [tool_result]})
        else:
            # Claude provided a final text answer
            text_block = next(
                b for b in response.content if hasattr(b, "text")
            )
            return text_block.text

Handling Multi-Step Questions

Claude naturally handles questions that require multiple queries. When asked "Compare this quarter's sales to the same quarter last year," Claude will execute two queries — one for each period — then synthesize the results into a comparison.

# Claude will automatically execute multiple queries
answer = ask_database(
    "Compare the average order value in January vs February, "
    "and tell me which product category drove the difference.",
    "sales.db"
)
print(answer)

Behind the scenes, Claude might execute three tool calls: one for January averages, one for February averages, and a third breaking down by product category. The conversation loop handles this seamlessly.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

Adding Guardrails

Before executing any query, validate it:

import sqlparse

def validate_query(sql: str) -> tuple[bool, str]:
    """Ensure the query is safe to execute."""
    parsed = sqlparse.parse(sql)
    if not parsed:
        return False, "Empty query"

    statement_type = parsed[0].get_type()
    if statement_type != "SELECT":
        return False, f"Only SELECT allowed, got {statement_type}"

    dangerous_keywords = ["DROP", "DELETE", "UPDATE", "INSERT", "ALTER", "TRUNCATE"]
    upper_sql = sql.upper()
    for keyword in dangerous_keywords:
        if keyword in upper_sql:
            return False, f"Forbidden keyword: {keyword}"

    return True, "OK"

Integrate this into the tool execution step so no unsafe query ever reaches the database.

FAQ

Does Claude handle complex JOINs as well as GPT-4?

Yes. Claude Sonnet and Opus both handle multi-table JOINs, subqueries, and CTEs with high accuracy. Claude tends to write more explicit JOIN conditions and is less likely to produce ambiguous column references, which reduces runtime errors in practice.

How does tool use differ from just asking Claude to output SQL?

With tool use, Claude can execute the query, see the results, and self-correct. If a query returns zero rows or an error, Claude can diagnose the problem and try a different approach. Single-shot SQL generation has no feedback loop, so errors are returned directly to the user.

What is the cost of running text-to-SQL with Claude?

A typical question requires 1-3 API calls. With Claude Sonnet, each call costs roughly $0.003-0.01 depending on the schema size and response length. For most applications, the cost per question is under $0.03, making it highly cost-effective compared to building custom NLU pipelines.


#Claude #Anthropic #TextToSQL #ToolUse #DatabaseAgent #AgenticAI #NaturalLanguageSQL #PythonAI

Share
C

Written by

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.

Related Articles You May Like

AI Interview Prep

8 AI System Design Interview Questions Actually Asked at FAANG in 2026

Real AI system design interview questions from Google, Meta, OpenAI, and Anthropic. Covers LLM serving, RAG pipelines, recommendation systems, AI agents, and more — with detailed answer frameworks.

AI Interview Prep

8 LLM & RAG Interview Questions That OpenAI, Anthropic & Google Actually Ask

Real LLM and RAG interview questions from top AI labs in 2026. Covers fine-tuning vs RAG decisions, production RAG pipelines, evaluation, PEFT methods, positional embeddings, and safety guardrails with expert answers.

AI Interview Prep

7 AI Coding Interview Questions From Anthropic, Meta & OpenAI (2026 Edition)

Real AI coding interview questions from Anthropic, Meta, and OpenAI in 2026. Includes implementing attention from scratch, Anthropic's progressive coding screens, Meta's AI-assisted round, and vector search — with solution approaches.

AI Interview Prep

7 Agentic AI & Multi-Agent System Interview Questions for 2026

Real agentic AI and multi-agent system interview questions from Anthropic, OpenAI, and Microsoft in 2026. Covers agent design patterns, memory systems, safety, orchestration frameworks, tool calling, and evaluation.

Learn Agentic AI

MCP Ecosystem Hits 5,000 Servers: Model Context Protocol Production Guide 2026

The MCP ecosystem has grown to 5,000+ servers. This production guide covers building MCP servers, enterprise adoption patterns, the 2026 roadmap, and integration best practices.

AI Interview Prep

6 AI Safety & Alignment Interview Questions From Anthropic & OpenAI (2026)

Real AI safety and alignment interview questions from Anthropic and OpenAI in 2026. Covers alignment challenges, RLHF vs DPO, responsible scaling, red-teaming, safety-first decisions, and autonomous agent oversight.