AIGC 时代,数据库开发者的新玩法:用大模型彻底告别手写 SQL(Text-to-SQL 实战)

0 阅读7分钟

前言

最近在学习 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)"

🔸 结构拆解:

  1. 开头固定部分

    "CREATE TABLE employees (\n"
    
    • 写死表名为 employees,并开始 CREATE TABLE 语句。
  2. 列表推导式生成每列定义

    [
        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),因此这种拼接方式会丢失复合主键信息。

  1. ",\n" 连接各列

    • 使输出格式美观,每列一行,逗号分隔。
  2. 结尾闭合括号

    + "\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

问题:开发部所有员工的姓名和工资,按工资从高到低排序
生成的 SQLSELECT name, salary FROM employees WHERE department = '开发部' ORDER BY salary DESC
执行结果: [('王磊', 38000), ('张伟', 35000), ('曹伟伟', 33000), ('陈昊', 32000)]

问题:销售部平均工资是多少?
生成的 SQLSELECT AVG(salary) FROM employees WHERE department = '销售部'
执行结果: [(19000.0,)]

问题:工资最高的前3名员工是谁?
生成的 SQLSELECT 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 年不会这个,真的会落后了!