前言
最近在学习 Text-to-SQL(自然语言转 SQL),发现这简直是 2025 年数据库开发的降维打击!过去写 SQL 要背一堆语法、查字段名、纠结 JOIN,现在直接扔一句中文给大模型,它就给你吐出完美可执行的 SQL。
今天把我的学习笔记 + 完整可运行代码整理成这篇干货,带你 30 分钟从零上手“AI 数据库助手”,以后你可能真的只需要会 CRUD 的自然语言版本就够了
一、为什么 AIGC 时代要重新看待数据库操作?
传统数据库开发痛点:
- SQL 语法繁琐,容易写错(尤其是多表 JOIN、分组、窗口函数)
- 新人上手慢,老鸟也经常查文档
- 前端/产品/运营想查个数据,还得找开发写 SQL
AIGC 带来的变革:
- 自然语言 → SQL(Text-to-SQL)
- 零 SQL 基础的人也能操作数据库
- 极大提升个人和团队的生产力
- 本地轻量数据库 + 大模型 API = 个人级超级生产力工具
二、主角登场:SQLite3 —— 最适合个人/小应用的数据库
为什么选 SQLite?
- 零配置、单文件、无服务器进程
- 微信、浏览器、手机 App 都在用它存本地数据
- Python 内置 sqlite3 模块,开箱即用
- 完美配合本地运行的大模型或云端 API
MySQL、PostgreSQL 适合大型分布式系统,但对个人项目完全杀鸡用牛刀。
三、完整实战:用 DeepSeek + SQLite 实现自然语言查数据库
1. 准备工作
Python
import sqlite3
from openai import OpenAI # DeepSeek 兼容 OpenAI SDK
2. 创建数据库和表,插入测试数据
Python
# 创建(或打开)数据库文件
conn = sqlite3.connect("company.db") # 会生成一个 company.db 文件
cursor = conn.cursor()
# 创建员工表
cursor.execute("""
CREATE TABLE IF NOT EXISTS employees (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
department TEXT,
salary INTEGER
)
""")
# 插入一批示例数据
sample_data = [
(1, "张伟", "开发部", 35000),
(2, "李娜", "销售部", 22000),
(3, "王磊", "开发部", 38000),
(4, "刘敏", "人事部", 18000),
]
cursor.executemany("INSERT OR REPLACE INTO employees VALUES (?, ?, ?, ?)", sample_data)
conn.commit()
3. 动态获取表结构(关键!让大模型知道字段名和类型)
Python
# 获取表结构信息
schema = cursor.execute("PRAGMA table_info(employees)").fetchall()
# 拼成 CREATE TABLE 语句字符串,方便喂给大模型
schema_str = "CREATE TABLE employees (\n" + ",\n".join([
f" {col[1]} {col[2].upper()}" + (" PRIMARY KEY" if col[5] else "")
for col in schema
]) + "\n)"
print("当前表结构:")
print(schema_str)
逐行重点解析
第1行:cursor.execute("PRAGMA table_info(employees)").fetchall()
-
作用:查询 SQLite 数据库中
employees表的元数据(即“表结构”)。 -
关键点:
-
PRAGMA table_info(table_name)是 SQLite 特有的命令,用于获取指定表的列信息。 -
返回结果是一个列表,每个元素是一个元组,代表一列的信息。
-
每个元组包含 6 个字段(按顺序):
索引 含义 示例值 0 列 ID(cid) 0 1 列名(name) 'id' 2 数据类型(type) 'INTEGER' 3 是否非空(notnull) 0 或 1 4 默认值(dflt_value) None 或 'N/A' 5 是否为主键(pk) 0 或 1(注意:1 表示是主键)
-
💡 注意:SQLite 的
PRAGMA table_info中,第6个字段(索引为5)为1表示该列是主键(即使复合主键也只有一列会被标记?实际上 SQLite 对复合主键支持有限,通常只有显式声明PRIMARY KEY的单列会被设为 pk=1)。
第2–5行:构建 CREATE TABLE 字符串
schema_str = "CREATE TABLE employees (\n" + ",\n".join([
f" {col[1]} {col[2].upper()}" + (" PRIMARY KEY" if col[5] else "")
for col in schema
]) + "\n)"
🔸 结构拆解:
-
开头固定部分:
"CREATE TABLE employees (\n"- 写死表名为
employees,并开始CREATE TABLE语句。
- 写死表名为
-
列表推导式生成每列定义:
[ f" {col[1]} {col[2].upper()}" + (" PRIMARY KEY" if col[5] else "") for col in schema ]-
col[1]:列名(如'id') -
col[2].upper():将类型转为大写(如'integer' → 'INTEGER',更符合 SQL 习惯) -
" PRIMARY KEY" if col[5] else "":- 如果
col[5] == 1(即该列是主键),就追加PRIMARY KEY - 否则不加
- 如果
-
⚠️ 局限性:此逻辑只能处理单列主键。如果表使用了复合主键(如 PRIMARY KEY (col1, col2)),PRAGMA table_info 不会直接体现这一点(所有列的 pk 都可能是 0),因此这种拼接方式会丢失复合主键信息。
-
用
",\n"连接各列:- 使输出格式美观,每列一行,逗号分隔。
-
结尾闭合括号:
+ "\n)"
输出:
CREATE TABLE employees (
id INTEGER PRIMARY KEY,
name TEXT,
department TEXT,
salary INTEGER
)
4. 配置 DeepSeek API(免费额度超多,性价比之王)
Python
client = OpenAI(
api_key="sk-your-deepseek-key", # 去 https://platform.deepseek.com 注册拿
base_url="https://api.deepseek.com"
)
5. 核心函数:自然语言 → SQL
Python
def ask_deepseek(query: str, schema: str) -> str:
prompt = f"""
你是一个专业的 SQL 专家。
以下是数据库表结构:
{schema}
请根据用户的问题,写出正确的 SQLite 语法 SQL 查询语句。
要求:
1. 只输出纯 SQL 语句,一行或多行都可以
2. 不要用 Markdown 代码块
3. 不要解释,不要有任何额外文字
4. 如果需要排序,用合理的方式(比如工资降序)
5. 字段名严格按照 schema 里面的拼写(注意是 department,不是 departerment)
用户问题:{query}
"""
response = client.chat.completions.create(
model="deepseek-deepseek-reasoner",
messages=[{"role": "user", "content": prompt}],
max_tokens=512,
temperature=0.1 # 确保 SQL 语法严谨
)
sql = response.choices[0].message.content.strip()
return sql
6. 实际测试几句自然语言查询
Python
questions = [ "开发部所有员工的姓名和工资,按工资从高到低排序", "销售部平均工资是多少?", "工资最高的前3名员工是谁?", "人事部有没有人?如果有列出姓名", "整个公司有多少员工?"]
for q in questions:
print(f"\n问题:{q}")
sql = ask_deepseek(q, schema_str)
print(f"生成的 SQL:{sql}")
try:
result = cursor.execute(sql).fetchall()
print("执行结果:", result)
except Exception as e:
print("SQL 执行出错:", e)
实际运行效果:
text
问题:开发部所有员工的姓名和工资,按工资从高到低排序
生成的 SQL:SELECT name, salary FROM employees WHERE department = '开发部' ORDER BY salary DESC
执行结果: [('王磊', 38000), ('张伟', 35000), ('曹伟伟', 33000), ('陈昊', 32000)]
问题:销售部平均工资是多少?
生成的 SQL:SELECT AVG(salary) FROM employees WHERE department = '销售部'
执行结果: [(19000.0,)]
问题:工资最高的前3名员工是谁?
生成的 SQL:SELECT name, salary FROM employees ORDER BY salary DESC LIMIT 3
执行结果: [('王磊', 38000), ('张伟', 35000), ('曹伟伟', 33000)]
几乎完美!即使你问得很模糊,它也会合理推断。
四、Prompt 工程是 Text-to-SQL 的灵魂
好的 Prompt 决定了 90% 的成功率,我的实战经验总结:
黄金 Prompt 模板(直接抄走就行):
text
你是一个专业的 SQLite 数据库工程师。
表结构如下:
{schema}
请严格按照以下要求输出:
1. 只输出可直接执行的 SQL 语句
2. 不要用 ``` 代码块包裹
3. 不要任何解释文字
4. 使用 SQLite 语法
5. 字段名大小写敏感,按实际来
6. 如果需要排序,默认工资降序、ID升序等合理方式
用户问题:{query}
额外技巧:
- temperature 设 0~0.2,越低越严谨
- 用 deepseek-reasoner 模型处理复杂多表 JOIN、窗口函数更强
- 复杂查询可以先让模型“思考步骤”(系统提示加 CoT)
五、未来:你可能真的不需要再手写 SQL 了
想象一下未来的开发场景:
- 产品经理:小G,昨天新注册用户的平均订单金额是多少?
- 你:直接把问题扔给 AI 数据库助手,秒出结果
- 数据分析、个人记账、爬虫存储、桌面小工具… 全都可以零 SQL 开发
本地 SQLite + 国产大模型 API(DeepSeek、Qwen、通义千问等)组合,成本几乎为零,隐私还完全掌握在自己手里。
最后
Text-to-SQL 不是要取代数据库工程师,而是让我们把精力从“写正确语法”解放出来,去做更高级的架构设计、数据建模、性能优化。
强烈建议每一位后端/全栈开发者都立刻上手玩一玩,2025 年不会这个,真的会落后了!