这一篇是 Tools of the Trade Linux and SQL 的配套深度文,把课程 Module 4 的 SQL 内容压成一张能审 AI 输出的速查。
先认 3 个名词,不认它你看 SQL 像看天书
AI 写 SQL 时反复出现的三个词,先钉死:
- Database——一个 SQL 文件柜。你公司的”用户库”、“订单库”是一个 database。
- Table——文件柜里的一张表。一张表 = 一类东西的集合(所有用户 / 所有订单)。
- Primary key / Foreign key——表和表怎么”认亲戚”。
- Primary key = 这张表的唯一身份证(每行不能重复、不能空)
- Foreign key = “我这一行的某列等于另一张表的 primary key”——这就是 JOIN 能跨表查的原理
看到 AI 写 users.id = orders.user_id——它在做的事就是”用 users 表的 primary key id 对上 orders 表的 foreign key user_id”。
任何 SQL 查询都只是在填 4 个 slot
AI 给你写出来的 SQL,90% 长这样:
SELECT [挑哪几列]
FROM [哪张表]
WHERE [什么条件]
ORDER BY [怎么排序];看一段就在脑里默念这 4 个 slot,看它填了什么、漏了什么。
Slot 1: SELECT ... — 挑列
SELECT name, email FROM users;AI 在做的事:只把 users 表的 name 和 email 两列拿出来,别的列(密码、地址)留在表里不动。
SELECT * FROM users;看到 *(“通配符”)警觉——它把这张表的所有列全拿出来,包括敏感字段。生产代码里 AI 给你写 SELECT *,90% 的情况你都要让它改成只挑必需列。
Slot 2: FROM ... — 哪张表
FROM users —— 从 users 表拿。一张表的查询,这一格最简单。复杂的是后面:
FROM users JOIN orders ON users.id = orders.user_id看到 JOIN——它在跨两张表拿数据(下面专门讲)。
Slot 3: WHERE ... — 什么条件
不写这一格 = 整张表全要。这是新人最容易让 AI 写出生产事故的地方。
SELECT * FROM users WHERE country = 'AU';AI 在做的事:只要 country 列等于字符串 ‘AU’ 的那些行。
| AI 写这个 | 意思 |
|---|---|
= | 完全相等(数值或字符串) |
!= 或 <> | 不等于 |
> < >= <= | 比大小(数字或日期) |
BETWEEN A AND B | A 和 B 之间(包含两端,这是个陷阱见下文) |
LIKE 'a%' | 模式匹配(通配符:% 任意串,_ 任意单字符) |
IS NULL / IS NOT NULL | 这一列是不是空值——这一定要用 IS,不能用 = |
Slot 4: ORDER BY ... — 怎么排
ORDER BY created_at DESC;AI 在做的事:按 created_at 列倒序排(最新的在前)。ASC 是正序(默认),DESC 是倒序。
不写这一格 = 数据库按它自己舒服的顺序返回——很可能不是你以为的那个顺序。生产报表里 AI 漏写 ORDER BY,导致每次刷新顺序不一样,排查时候很折磨。
4 种 JOIN — 一张图看懂
这是这门课最大的考点,也是 AI 写 SQL 时最容易在你审不出错的地方藏 bug 的地方。
只看一个问题就好:“匹配不上的那些行怎么办”。
| AI 写这个 | ”匹配不上”怎么办 |
|---|---|
INNER JOIN | 两边都丢掉 — 只留两张表都匹配上的行 |
LEFT JOIN | 保留左表全部,右表没匹配的位置填 NULL |
RIGHT JOIN | 保留右表全部,左表没匹配的位置填 NULL |
FULL OUTER JOIN | 两边都留,匹配不上的位置都填 NULL |
举一个能记一辈子的例子:你有 users 表(10 个用户)和 orders 表(7 个用户下过单)。
SELECT u.name, o.id
FROM users u INNER JOIN orders o ON u.id = o.user_id;
-- 返回 7 行 (只有下过单的)
SELECT u.name, o.id
FROM users u LEFT JOIN orders o ON u.id = o.user_id;
-- 返回 10 行 (10 个用户全部,没下过单的 o.id 是 NULL)AI 在做”用户报表”,但只 INNER JOIN——3 个没下单的用户在报表里直接消失了。看不出错,但数据缺了——这是 JOIN 类的 silent bug。
4 个 silent bug 信号 — 看到要小心
这 4 种写法 SQL 不报错,但返回结果跟你以为的不一样——是 AI 写代码最阴险的坑。
1. WHERE x = NULL — 永远返回空集
NULL 在 SQL 里不等于自己。x = NULL 永远 false,所以这一句永远不返回任何行。
-- ❌ AI 写这个 — 永远没结果,也不报错
SELECT * FROM users WHERE email = NULL;
-- ✅ 正确写法
SELECT * FROM users WHERE email IS NULL;2. AND 比 OR 优先
不加括号时,AND 先算,OR 后算:
-- AI 写: country='AU' OR country='NZ' AND status='active'
-- 实际执行: country='AU' OR (country='NZ' AND status='active')
-- 你以为的: (country='AU' OR country='NZ') AND status='active'看到 OR 和 AND 混用,立刻找括号——没括号就让 AI 加。
3. BETWEEN 是闭区间
WHERE created_at BETWEEN '2025-01-01' AND '2025-12-31'包含 1 月 1 日和 12 月 31 日两头。AI 给你做”过去 30 天”如果用 BETWEEN,边界数据是否算进去,你要确认。
4. 字符串和日期要引号,数字不要
WHERE age = 25 -- ✅ 数字不引号
WHERE name = 'Shawn' -- ✅ 字符串单引号
WHERE created_at > '2025-01-01' -- ✅ 日期当字符串处理,要引号
WHERE age = '25' -- ⚠️ 能跑但有隐式转换,大表会慢还要留意一个安全坑:SQL Injection
AI 给你写 SQL 时,如果它把用户输入直接拼到字符串里,你看到这种 pattern 要立刻喊停:
# ❌ AI 写这个 — 经典 SQL Injection 入口
query = "SELECT * FROM users WHERE name = '" + user_input + "'"
# ✅ 正确做法 — 用 [[prepared-statement|prepared statement]]
query = "SELECT * FROM users WHERE name = ?"
cursor.execute(query, [user_input])第一种写法,用户输入 ' OR '1'='1 就能拖走整张表。AI 不主动用 prepared statement 时,你必须主动让它改。
看懂 AI 写的 SQL,4 个 slot 过一遍就够了
读到任何 AI 写的 SQL,按这个顺序在脑里默念一遍:
- 挑哪几列?有没有
*漏出敏感字段? - 哪张表?JOIN 的时候”匹配不上”怎么办?
- 什么条件?
NULL用了IS没?AND/OR有没有括号? - 怎么排?要不要
ORDER BY保证稳定顺序?
4 个 slot 过完,90% 的 AI 写的 SQL 你都能审出问题。剩下 10% 是 GROUP BY / 窗口函数 / CTE 这种你真用到再说——大多数日常审 AI 输出,这一张速查就够。
AI 写 SQL 比你快。但让 AI 写完没人审 = 安心地把刀递给一个看不懂结构的人。 你需要的从来不是写得比 AI 快,是看得比 AI 快。