组合条件
AND 留下两边都为真的行,OR 留下任一为真的行。写出来,这是在问:已支付或已发货、并且金额超过 500 的订单。
1
SELECT order_number, status, total
FROM orders
WHERE (status = 'paid' OR status = 'shipped')
AND total > 500
ORDER BY total DESC
LIMIT 20;
结果 — 共 20 行,这里是前 5 行
| order_number | status | total |
|---|---|---|
| ORD-2025-002767 | shipped | 30906.66 |
| ORD-2022-001901 | shipped | 28151.01 |
| ORD-2023-001772 | paid | 26797.87 |
| ORD-2024-001907 | shipped | 26648.91 |
| ORD-2025-002847 | paid | 25837.57 |
浏览器会另开一个标签页打开 Planche,示例数据库已经载入,这条查询也已经放好。本页其他示例都会复用同一个标签页;在你按下 F9 之前,什么都不会执行。
括号会改变条件的组合方式。把同样的条件去掉括号后再运行一次:
2
-- The same words without the brackets. AND binds tighter than OR,
-- so this reads as: paid (any total) OR shipped-and-over-500.
SELECT order_number, status, total
FROM orders
WHERE status = 'paid' OR status = 'shipped' AND total > 500
ORDER BY total DESC
LIMIT 20;
结果 — 共 20 行,这里是前 5 行
| order_number | status | total |
|---|---|---|
| ORD-2025-002767 | shipped | 30906.66 |
| ORD-2022-001901 | shipped | 28151.01 |
| ORD-2023-001772 | paid | 26797.87 |
| ORD-2024-001907 | shipped | 26648.91 |
| ORD-2025-002847 | paid | 25837.57 |
答案变了,因为 AND 比 OR 结合得更紧——就像 × 比 + 更紧一样。没有括号,数据库读到的是"已支付、金额不限,或者 已发货且超过 500",于是每一笔小额已支付订单也都回来了。
匹配若干个值中的一个
一串比较同一个列的 OR,正是 IN 该出场的地方。
3
SELECT order_number, status, total, ordered_at
FROM orders
WHERE status IN ('paid', 'shipped', 'delivered')
ORDER BY ordered_at DESC
LIMIT 20;
结果 — 共 20 行,这里是前 5 行
| order_number | status | total | ordered_at |
|---|---|---|---|
| ORD-2025-002480 | shipped | 6333.77 | 2025-12-28 23:52:14 |
| ORD-2025-000505 | delivered | 2276.51 | 2025-12-28 11:16:39 |
| ORD-2025-001581 | delivered | 2645.06 | 2025-12-28 06:12:38 |
| ORD-2025-000995 | delivered | 2584.02 | 2025-12-28 05:47:53 |
| ORD-2025-003219 | delivered | 561.48 | 2025-12-28 03:20:37 |
status IN ('paid', 'shipped', 'delivered') 说的就是三个 OR 要说的话,而且只说了一遍。取反是 NOT IN——它有一个和 NULL 有关的锋利边角,会在子查询那一课单独用一节来讲。
区间
BETWEEN a AND b 是 >= a AND <= b 的简写,两端都包含。
4
SELECT order_number, ordered_at, total
FROM orders
WHERE ordered_at BETWEEN '2025-01-01' AND '2025-01-31 23:59:59'
ORDER BY ordered_at
LIMIT 20;
结果 — 共 20 行,这里是前 5 行
| order_number | ordered_at | total |
|---|---|---|
| ORD-2025-003412 | 2025-01-01 00:18:52 | 2806.57 |
| ORD-2025-003616 | 2025-01-01 11:18:14 | 6955.62 |
| ORD-2025-001503 | 2025-01-01 23:43:34 | 5837.23 |
| ORD-2025-000317 | 2025-01-02 05:08:32 | 15130.7 |
| ORD-2025-001298 | 2025-01-02 18:36:32 | 5045.04 |
模式
LIKE 按模式比较,其中 % 代表任意长度的字符,_ 代表恰好一个字符。
5
SELECT first_name, last_name, email
FROM customers
WHERE email LIKE '%@inbox.example'
ORDER BY last_name
LIMIT 20;
结果 — 共 20 行,这里是前 5 行
| first_name | last_name | |
|---|---|---|
| Freya | Ahmed | freya.ahmed@inbox.example |
| Hugo | Ahmed | hugo.ahmed@inbox.example |
| Jonas | Ahmed | jonas.ahmed@inbox.example |
| Kenji | Ahmed | kenji.ahmed@inbox.example |
| Liam | Ahmed | liam.ahmed@inbox.example |
缺失的值
这些客户里有 279 位没有记录电话号码。就是这些人:
6
SELECT id, first_name, last_name, phone
FROM customers
WHERE phone IS NULL
LIMIT 20;
结果 — 共 20 行,这里是前 5 行
| id | first_name | last_name | phone |
|---|---|---|---|
| 2 | Mateo | Costa | NULL |
| 9 | Sven | Smith | NULL |
| 21 | Layla | Fischer | NULL |
| 25 | Freya | Nguyen | NULL |
| 28 | Priya | Jang | NULL |
而下面这条,是大多数人第一次会写的:
7
-- 279 customers have no phone number, and this finds none of them.
SELECT id, first_name, last_name, phone
FROM customers
WHERE phone = NULL;
没有匹配的行
零行。不是报错,也不是警告——就是一张空网格。
NULL 不是一个值,而是值的缺失,所以任何与它的比较都不可能为真。phone = NULL 问的是"这个未知的东西是否等于那个未知的东西",诚实的答案是"未知",而未知不等于真,于是这一行被丢掉。NULL = NULL 同样不为真。唯一管用的判断是 IS NULL 和 IS NOT NULL。
现在你能做什么
针对一张表,你几乎能表达任何条件。剩下的限制仍然是一切都在一张表里——而值得问的问题通常不在。