「帮我查一下上个月消费最高的 5 个用户」——这种问题,过去得会写 SQL。现在你可以直接用中文问 AI,让它写出查询语句。这叫 text-to-SQL。本教程带你从建库、给结构、问问题,到把查询固化成小工具,全程强调「核对」,避免 AI 一本正经地胡写。
🗄️ 本教程适合:运营、产品、分析师等「想查数据但不熟 SQL」的同学;也适合开发者做快速原型。
先搞懂:为什么必须给 AI 看「表结构」?
AI 不知道你数据库里有什么表、列叫什么。如果你只说「查消费最高的用户」,它只能凭空猜列名,十有八九写出错 SQL。把表结构(schema)连同问题一起给它,是 text-to-SQL 成功的关键。
| 只给问题 | 给问题 + schema |
|---|---|
| AI 瞎编 users / orders 表 | AI 按真实表名列名写 |
| 易报「表不存在」 | 查询能直接跑通 |
Step 1:准备一个示例数据库
1 先有表,AI 才有依据
用轻量的 SQLite 建两张表当练习场:
import sqlite3
con = sqlite3.connect("demo.db")
con.executescript('''
CREATE TABLE users(id INTEGER, name TEXT, city TEXT);
CREATE TABLE orders(id INTEGER, user_id INTEGER, amount REAL, day TEXT);
INSERT INTO users VALUES(1,'小红','北京'),(2,'小明','上海');
INSERT INTO orders VALUES(1,1,199.0,'2026-08-01'),(2,1,59.0,'2026-08-02'),(3,2,320.0,'2026-08-01');
''')
con.commit()
💡 真实项目里,把 schema(建表语句)导出一份给 AI 即可,不必给数据本身。
Step 2:把「表结构 + 问题」一起给 AI
2 上下文给足,SQL 才靠谱
关键提示词模板:
你是一个 SQL 专家。下面是表结构:
CREATE TABLE users(id, name, city);
CREATE TABLE orders(id, user_id, amount, day);
请用 SQLite 语法回答:「每个城市有多少用户?」
只输出 SQL,不要解释。
指定方言:MySQL、PostgreSQL、SQLite 的语法有差异(如日期函数、分页)。一定写明你要哪种,否则 AI 可能混用。
Step 3:单表查询起步
3 先搞定「一张表」
问法越具体,SQL 越准。比如:
问题:统计每个城市的用户数
→ SELECT city, COUNT(*) FROM users GROUP BY city;
问题:消费金额大于 100 的订单有哪些
→ SELECT * FROM orders WHERE amount > 100;
🔍 新手建议从单表 WHERE / GROUP BY 起步,确认 AI 写对了再上复杂查询。
Step 4:多表 JOIN 与聚合
4 跨表关联才显威力
「消费最高的前 5 名用户及其订单数」需要连表:
SELECT u.name, SUM(o.amount) AS total, COUNT(o.id) AS orders
FROM users u
JOIN orders o ON o.user_id = u.id
GROUP BY u.id
ORDER BY total DESC
LIMIT 5;
JOIN 条件要对:连错字段会得到翻倍或空的怪结果。让 AI 解释它的 JOIN 逻辑,确认关联键无误。
Step 5:核对 AI 生成的 SQL(最重要的一步)
5 先在小库试跑,别直接上生产
AI 可能「幻觉」出不存在的列。上线前务必:
1. 在测试库 / 样本数据上先跑,看结果是否合理
2. 逐列核对:SQL 里的列名是否真在你的表里
3. 对聚合结果做个「手算抽查」(如总数是否对得上)
4. 只读查询用只读账号;禁止 AI 生成的写操作直接跑
✅ 经验法则:AI 写的 SQL 默认当「草稿」,你验证过才执行。涉及 UPDATE/DELETE 更要人工复核。
Step 6:固化成可复用小工具
把「中文→SQL→结果」做成一个脚本,以后只改问题:
import sqlite3, os
from openai import OpenAI
client = OpenAI(api_key=os.environ.get("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com")
SCHEMA = "CREATE TABLE users(id,name,city); CREATE TABLE orders(...);"
def ask(q):
prompt = f"表结构:\n{SCHEMA}\n用SQLite回答:{q}\n只输出SQL"
sql = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role":"user","content":prompt}]).choices[0].message.content
con = sqlite3.connect("demo.db")
return con.execute(sql).fetchall() # 仅只读查询
安全清单:连只读副本;禁止 AI 生成写操作直跑;含个人信息的数据先脱敏;生产库绝不暴露给公网模型。
常见问题速查
| 现象 | 大概率原因 & 解决 |
|---|---|
| 报错「no such column」 | AI 编了列名;把真实 schema 给它 |
| 结果数量翻倍 | JOIN 键写错导致笛卡尔积 |
| 语法报错 | 方言不对;明确要 SQLite/MySQL 等 |
| 怕误改数据 | 只用只读账号跑 SELECT |