企业想让 AI 查自己的数据,第一个撞上的墙不是模型能力,是它不知道你的表长什么样。
你把"上季度华东区毛利最低的 10 个客户"扔给 ChatGPT,它只能编一个看起来像 SQL 的东西——表名是猜的、字段是猜的、连数据库类型都不知道。
这篇讲怎么把这件事做对:四段提示词 + 一道安全闸,拼成一条从"人话"到"可用数据"的完整流水线。代码我用 SQLite 建了真实业务库跑通,不是伪代码。
一、先看这条流水线的全貌
| ① 生成 | 人话 → SQL | 业务/分析师 | id=5011 AI2SQL 查询生成器 |
| ② 讲解 | SQL → 人话 + 风险提示 | 业务方确认、DBA 审核 | id=2299 面向非工程师的 SQL 查询讲解 |
| ③ 安全执行 | 只读闸 + 强制 LIMIT + 超时 | 工程侧 | 本文代码(第三节) |
| ④ 反向入库 | 纸质/PDF/截图表格 → 结构化数据 | 数据还没进系统时 | id=1193 PDF 表格转 CSV、id=4765 Excel 表格助手 |
为什么必须有②③两站:多数"AI 查数据库"的教程只讲①,然后直接执行。这在生产环境是事故——AI 可能生成一个没有 WHERE 的全表更新,或者把含手机号的表整张导出去。②是让人看懂风险,③是让机器拦住风险,两站都不能省。
结论:AI 取数的难点不在生成 SQL,在"生成之后谁为它负责"。
二、站① 生成 SQL:提示词要给三样东西
提示岛站内条目 id=5011「AI2SQL 查询生成器」(CC0-1.0,1123 字),全文:
Context:
This prompt is used by AI2sql to generate SQL queries from natural language.
AI2sql focuses on correctness, clarity, and real-world database usage.
Purpose:
This prompt converts plain English database requests into clean,
readable, and production-ready SQL queries.
Database:
${db:PostgreSQL | MySQL | SQL Server}
Schema:
${schema:Optional — tables, columns, relationships}
User request:
${prompt:Describe the data you want in plain English}
Output:
– A single SQL query that answers the request
Behavior:
– Focus exclusively on SQL generation
– Prioritize correctness and clarity
– Use explicit column selection
– Use clear and consistent table aliases
– Avoid unnecessary complexity
Rules:
– Output ONLY SQL
– No explanations
– No comments
– No markdown
– Avoid SELECT *
– Use standard SQL unless the selected database requires otherwise
Ambiguity handling:
– If schema details are missing, infer reasonable relationships
– Make the query work on a typical schema of that kind
三个关键设计,值得抄进你自己的提示词:
⚠️ 它的 Ambiguity handling 写了"schema 缺失时推断合理关系"——这在生产上是危险的。宁可让它报错,也别让它猜表结构。建议把这条改成:“If schema is missing, ask for it; do not invent table or column names.”
结论:Text2SQL 提示词的核心不是"帮我写 SQL",是"先给你 schema,再让你只输出 SQL"。
三、站② 讲解 SQL:让业务方看懂,也看出风险
生成的 SQL 不能直接跑,得有人确认"这是不是我要的"。但业务同事看不懂 SQL——这一站就是给他翻译的。
提示岛站内条目 id=2299「面向非工程师的 SQL 查询讲解」(351 字),全文:
Explain this SQL for a non-engineer stakeholder.
SQL:
${sql}
Also provide:
– What business question it answers
– Tables/joins in plain words
– Filters and date ranges
– Risks (cartesian joins, missing filters, PII exposure)
– A one-paragraph executive summary
Assume the reader knows spreadsheets but not SQL. Do not rewrite the query unless asked.
这段短,但设计密度很高:
- Assume the reader knows spreadsheets but not SQL——锚定读者认知水平,AI 就不会用"外连接基数"这种词,而会说"像 VLOOKUP 那样匹配"
- Risks (cartesian joins, missing filters, PII exposure)——显式点名三类风险:笛卡尔积(join 条件漏了导致数据爆炸)、缺过滤条件(全表扫描)、PII 泄露。这三个正是 AI 生成 SQL 最常犯的错
- Do not rewrite the query unless asked——防止 AI 自作主张改 SQL,改了就和实际要执行的不一致了
在企业里的实际用法:把它做成一个固定环节——AI 生成 SQL 后,自动再调一次这个提示词,把"这段查询在做什么 + 有什么风险"一起发给业务方确认。业务方点确认了才执行。多一次调用,少一次事故。
结论:AI 写的 SQL 要 AI 自己解释一遍给业务方看,确认环节不能省——这是责任划分,不是效率问题。
四、站③ 执行前的安全闸(完整代码,SQLite 实测跑通)
三道闸:只读账号(权限层,最根本)、语句白名单(只放行 SELECT)、强制 LIMIT + 超时。
"""AI 取数流水线:schema 提取 → 生成 SQL → 讲解 → 安全执行。SQLite 版,可直接跑。"""
import re
import sqlite3
DB_PATH = "business.db"
def build_demo_db(path=DB_PATH):
"""建一个演示业务库(真实场景替换为你的库连接)。"""
con = sqlite3.connect(path)
con.executescript("""
DROP TABLE IF EXISTS orders;
DROP TABLE IF EXISTS customers;
CREATE TABLE customers(
id INTEGER PRIMARY KEY, name TEXT, region TEXT, phone TEXT
);
CREATE TABLE orders(
id INTEGER PRIMARY KEY, customer_id INTEGER,
amount REAL, cost REAL, order_date TEXT
);
INSERT INTO customers VALUES
(1,'甲公司','华东','13800000001'),
(2,'乙公司','华东','13800000002'),
(3,'丙公司','华南','13800000003');
INSERT INTO orders VALUES
(1,1,10000,7000,'2026-07-05'),
(2,1,20000,18000,'2026-08-11'),
(3,2,15000,9000,'2026-09-02'),
(4,3,8000,3000,'2026-09-20');
""")
con.commit()
con.close()
def get_schema(con) –> str:
"""闸0:只把表结构喂给 AI,绝不把数据喂给它(防 PII 外泄)。"""
rows = con.execute(
"SELECT name, sql FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'"
).fetchall()
return "\\n".join(sql for _, sql in rows if sql)
FORBIDDEN = re.compile(
r"\\b(insert|update|delete|drop|alter|create|truncate|replace|attach|pragma|vacuum)\\b",
re.I,
)
def assert_read_only(sql: str) –> None:
"""闸1:语句白名单——只放行单条 SELECT/WITH。"""
s = sql.strip().rstrip(";").strip()
if ";" in s:
raise PermissionError("不允许多语句(防 SQL 注入拼接)")
if not re.match(r"^(select|with)\\b", s, re.I):
raise PermissionError(f"只允许 SELECT/WITH 查询,收到:{s[:40]}…")
m = FORBIDDEN.search(s)
if m:
raise PermissionError(f"查询中含写操作关键字 {m.group().upper()},已拦截")
def ensure_limit(sql: str, max_rows: int = 100) –> str:
"""闸2:强制 LIMIT,防全表拉取。"""
s = sql.strip().rstrip(";").strip()
if re.search(r"\\blimit\\b", s, re.I):
return s
return f"{s} LIMIT {max_rows}"
def run_query(sql: str, max_rows: int = 100, timeout_ms: int = 3000):
"""执行:只读连接 + 超时 + LIMIT。返回 (列名, 行)。"""
assert_read_only(sql)
safe_sql = ensure_limit(sql, max_rows)
con = sqlite3.connect(f"file:{DB_PATH}?mode=ro", uri=True) # 只读模式打开
try:
con.execute("PRAGMA busy_timeout = %d" % timeout_ms)
cur = con.execute(safe_sql)
cols = [d[0] for d in cur.description] if cur.description else []
return cols, cur.fetchall()
finally:
con.close()
def build_prompt(question: str, schema: str) –> str:
"""组装站①的提示词(id=5011 的结构:db + schema + request)。"""
return f"""Database: SQLite
Schema:
{schema}
User request: {question}
Output ONLY SQL. No explanations, no comments, no markdown.
Avoid SELECT *. Do not invent table or column names not in the schema.
If the schema is insufficient, reply exactly: NEED_MORE_SCHEMA
"""
if __name__ == "__main__":
build_demo_db()
con = sqlite3.connect(DB_PATH)
schema = get_schema(con)
con.close()
q = "各区域按毛利(amount-cost)从高到低列出客户名与毛利"
prompt = build_prompt(q, schema)
print("=== 发给大模型的提示词(前 400 字)===\\n", prompt[:400], "\\n")
# 这里替换成真实大模型调用;演示用固定 SQL 验证后续三道闸
fake_llm_sql = """
SELECT c.name, c.region, SUM(o.amount – o.cost) AS gross_profit
FROM orders o JOIN customers c ON c.id = o.customer_id
GROUP BY c.name, c.region ORDER BY gross_profit DESC
"""
cols, rows = run_query(fake_llm_sql)
print("=== 查询结果 ===")
print(" | ".join(cols))
for r in rows:
print(" | ".join(str(x) for x in r))
# 三道闸的拦截演示
print("\\n=== 安全闸拦截测试 ===")
for bad, why in [
("DELETE FROM orders", "写操作"),
("SELECT * FROM customers; DROP TABLE orders", "多语句拼接"),
("SELECT name, phone FROM customers", "无 LIMIT(应自动补)"),
]:
try:
c2, r2 = run_query(bad)
print(f" [放行] {why} → 返回 {len(r2)} 行")
except PermissionError as e:
print(f" [拦截] {why} → {e}")
这段代码的三道闸分别拦什么(我实测跑过,拦截结果见下):
| 只读连接 | sqlite3.connect("file:…?mode=ro", uri=True) | AI 生成的写语句在数据库层就没权限(最根本的一道) |
| 语句白名单 | assert_read_only() | DELETE FROM orders、多语句拼接 SELECT …; DROP TABLE … |
| 强制 LIMIT | ensure_limit() | AI 忘了加 LIMIT 导致全表拉取、把含手机号的客户表整张导出 |
⚠️ 还有一道最容易被忽略的闸在 get_schema():喂给大模型的只有表结构,没有数据。很多企业实现直接把 SELECT * FROM customers LIMIT 10 的结果贴进提示词当"示例数据"——那等于把客户手机号发给第三方模型 API。要示例就用假数据。
结论:AI 取数的安全边界靠四层——只读账号、语句白名单、强制 LIMIT、只给 schema 不给数据。少一层都可能出事故。
五、站④ 反向:数据还没进系统时怎么办
上面三站的前提是数据已经在数据库里。但企业常见的情况是:数据在 PDF、纸质表格、截图里——这时候要先把它结构化,AI 才处理得了。
① PDF/图片表格转 CSV——提示岛 id=1193(635 字),全文:
"Attached is an image of a table listing the model parameters for the ${insert_model_name} model (from [Insert Author/Paper Name]).
Please extract the data and convert it into a CSV code block that I can copy and save directly.
Requirements:
Use the first row as the header.
If cells are merged, repeat the value for each row to ensure the CSV is flat and processable.
Do not include units in the numeric columns (e.g., remove 'ms' or '%'), or keep them consistent in a separate column.
If any text is unclear due to image quality, mark it as '${unclear}' rather than guessing.
Ensure all fields containing commas are properly quoted."
两条设计特别值得学:
- If cells are merged, repeat the value for each row to ensure the CSV is flat——合并单元格摊平。这是表格提取最常见的坑:合并单元格直接转 CSV 会出现空值,后续没法处理
- If any text is unclear, mark it as '${unclear}' rather than guessing——看不清就标记,不许猜。财务/业务数据里猜错一个数字比留空严重得多
② 让 AI 当 Excel 用——提示岛 id=4765(CC0-1.0,499 字):
I want you to act as a text based excel. you'll only reply me the text-based 10 rows excel sheet with row numbers and cell letters as columns (A to L). First column header should be empty to reference row number. I will tell you what to write into cells and you'll reply only the result of excel table as text, and nothing else. Do not write explanations. i will write you formulas and you'll execute formulas and you'll only reply the result of excel table as text. First, reply me the empty sheet.
用法:把 CSV 数据贴进去,让 AI 按 Excel 语义算(写公式它执行)。适合小数据量的快速验算——比如站③查出来的毛利,想再算个占比、排个序,不用写第二段 SQL。⚠️ 但它只有 10 行 × A-L 列,大数据量别用,会截断。
结论:数据没进系统时,先用"表格提取"提示词把它变成 CSV;记住两条铁律——合并单元格要摊平、看不清要标记不许猜。
六、企业落地最容易翻车的三个地方
翻车点 1:把"能生成 SQL"当成"能上生产"
演示环境跑通不等于能上生产。上生产前必须补齐:只读账号(DBA 开权限,不是应用层限制)、查询超时与并发上限(AI 生成的烂 SQL 可能拖死库)、审计日志(谁问了什么、生成了什么 SQL、查出多少行——出问题要能追溯)。
翻车点 2:schema 一变,提示词就悄悄失效
数据库加了字段、改了表名,AI 还在用旧 schema 生成 SQL——它不会报错,会生成一个语法正确但结果错误的查询。对策:schema 从数据库实时拉取(像代码里的 get_schema()),不要硬编码在提示词里;关键报表的 SQL 生成后固化成视图,别每次都让 AI 重写。
翻车点 3:PII 从两个口子漏出去
- 口子一:喂 schema 时顺手带了示例数据(含真实手机号)→ 只给结构不给数据
- 口子二:AI 生成 SELECT * 把敏感列全查出来 → 提示词里 Avoid SELECT *,执行层再按列白名单过滤
id=2299 那段提示词把 PII exposure 明写进 Risks 清单,就是因为它真的是高频事故点。
结论:AI 取数上生产的三道门槛是权限、审计、schema 时效性——技术验证只占整件事的三分之一。
七、这四段提示词去哪找
四段都来自提示岛(prompts.ssjintaitong.com),站内这个方向的库存实测很厚:SQL 类文字提示词 114 条、Excel 类 112 条(抽样确认名实相符),另有数据分析类 12 条、数据库类若干。
这个站的定位是 AI 提示词与 Skill 库,收录超万条内容,其中文字提示词 3485 条(完整全文、一键复制)。75% 的条目标注了原始来源链接、68% 标注了开源许可证(以 MIT、CC0、CC-BY-4.0 为主),采集条目附 GitHub 出处可溯源——本文 4 段都标了条目 id(其中 2 段站内标注 CC0-1.0),可自行核对。免登录、免注册。
实用入口:
- 本文 4 段原文:prompts.ssjintaitong.com/prompts/5011、/prompts/2299、/prompts/1193、/prompts/4765
- SQL 类提示词:站内搜「SQL」(114 条);Excel 类搜「Excel」(112 条)
- 文字提示词总库:prompts.ssjintaitong.com/prompts?type=text
- 企业 AI 集成专题(含飞书 API 对接 7 篇教程):prompts.ssjintaitong.com/topic/enterprise-ai-integration
- 飞书 AI 自动化专题(148 条):prompts.ssjintaitong.com/topic/feishu
- Skill 质量评分报告:prompts.ssjintaitong.com/quality-report
搜索技巧:用能力词搜,别用系统名。搜「ERP」命中的多是无关内容,搜「SQL」「数据分析」「表格」直接命中可用的提示词。
下一篇预告
企业 AI 集成系列下一篇写财务场景:发票核对 → 凭证 → 报表分析。说句实话——财务这块我会写得慢一些,因为站内真正对口的财务提示词不多(多数"财务报表""审计"类条目实际是美股 K 线图或 SEO 审计,名实不符),我不想凑数硬写。宁可晚一点,也要每段提示词都能真用上。
本文 4 段提示词全文摘自提示岛站内条目(id=5011 / 2299 / 1193 / 4765),未做修改,均通过 prompt 注入内容检测;SQL 安全闸代码用 SQLite 建真实业务库实测跑通(含三道闸拦截验证);条目数与站点规模为 2026-10-31 实测;企业落地建议为笔者实务判断,具体权限与审计方案请咨询你的 DBA。
网硕互联帮助中心







评论前必须登录!
注册