这一篇是 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 表的 nameemail 两列拿出来,别的列(密码、地址)留在表里不动。

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 BA 和 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. ANDOR 优先

不加括号时,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'

看到 ORAND 混用,立刻找括号——没括号就让 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,按这个顺序在脑里默念一遍:

  1. 挑哪几列?有没有 * 漏出敏感字段?
  2. 哪张表?JOIN 的时候”匹配不上”怎么办?
  3. 什么条件?NULL 用了 IS 没?AND/OR 有没有括号?
  4. 怎么排?要不要 ORDER BY 保证稳定顺序?

4 个 slot 过完,90% 的 AI 写的 SQL 你都能审出问题。剩下 10% 是 GROUP BY / 窗口函数 / CTE 这种你真用到再说——大多数日常审 AI 输出,这一张速查就够。


AI 写 SQL 比你快。但让 AI 写完没人审 = 安心地把刀递给一个看不懂结构的人。 你需要的从来不是写得比 AI 快,是看得比 AI 快