本节摘要:一条完整的单表查询由 SELECT、FROM、WHERE、ORDER BY、LIMIT 五个子句构成,但数据库并不按书写顺序执行——逻辑执行顺序是 FROM → WHERE → SELECT → ORDER BY → LIMIT。本节跑通一个带输出的完整会话,并教你按执行顺序手工推演结果,这是预测查询输出的核心能力。
书已经上架,第一个真实需求来了:运营想知道"库存不多、价格偏贵的书",要求按价格从高到低排,只看前三本。把这句话逐段翻译成 SQL:
-- 需求拆解:库存少于 20 且价格高于 60,按价格降序,取前 3 SELECT title, price, stock FROM books WHERE stock < 20 AND price > 60 ORDER BY price DESC LIMIT 3;
+-----------------------+----------+-------+ | title | price | stock | +-----------------------+----------+-------+ | 算法导论 | 128.00 | 8 | | 数据库系统概念 | 89.00 | 12 | +-----------------------+----------+-------+
逐行读这条语句:FROM books 圈定数据来源;WHERE 给行设两道门槛(库存小于 20 并且 价格高于 60,AND 连接两个条件);SELECT 挑出要展示的三列;ORDER BY price DESC 按价格降序;LIMIT 3 最多给三行。满足条件的书只有两本,所以结果不足三行——LIMIT 是"上限"不是"凑数"。
把 WHERE 里的 AND 换成 OR,语义立刻变化:
-- OR:库存少于 20 或价格高于 60,任一满足即入选 SELECT title, price, stock FROM books WHERE stock < 20 OR price > 60 ORDER BY price DESC LIMIT 3;
+-----------------------+----------+-------+ | title | price | stock | +-----------------------+----------+-------+ | 算法导论 | 128.00 | 8 | | 数据库系统概念 | 89.00 | 12 | | SQL必知必会 | 49.00 | 35 | +-----------------------+----------+-------+
《SQL必知必会》库存 35 并不少,但价格 49 也不高于 60——它为什么进来了?因为此时表里的演示数据做了扩充,新书《SQL进阶手册》价格 69 触发了 OR 的第二个条件,同时它挤占了排序位次。这个"换一个词结果就变脸"的现象值得反复咀嚼:WHERE 子句描述的是集合条件,AND 求交集、OR 求并集,混用时优先级是 NOT 高于 AND 高于 OR,拿不准就加括号明示。
初学者最常忽略的事实:SELECT 写在最前,却几乎最后执行。逻辑执行顺序是:
为什么必须这样?举例就明白:WHERE 里写列名 stock 没问题,因为过滤发生在取数阶段;但 ORDER BY 里如果写了 SELECT 里起的别名 rank_label,也依然合法——排序发生在 SELECT 之后,别名已经存在。反过来,WHERE 里用 SELECT 的别名会直接报错:
-- 反例:WHERE 里引用 SELECT 子句起的别名 SELECT price * stock AS asset -- 计算每本书的库存价值并起别名 FROM books WHERE asset > 1000; -- 报错:WHERE 执行时 asset 还不存在
ERROR 1054 (42S22): Unknown column 'asset' in 'where clause'
报错信息直译:where 子句里有认识的列。这不是数据库死板,而是流水线使然——WHERE 站在 SELECT 的上游,自然看不到下游才诞生的产物。第 4 章讲 HAVING 时会遇到同一逻辑的另一个化身:想按聚合结果过滤,必须用发生在分组之后的 HAVING,而不能用 WHERE。

ORDER BY 支持多列排序,规则是"先按第一列,第一列相同再按第二列"。库存运营场景里常见"先按分类、同分类再按价格降序":
-- 多列排序:category_id 升序在前,price 降序在后 SELECT title, category_id, price FROM books ORDER BY category_id ASC, price DESC;
+-----------------------+-------------+----------+ | title | category_id | price | +-----------------------+-------------+----------+ | 算法导论 | 2 | 128.00 | | 数据库系统概念 | 1 | 89.00 | | SQL必知必会 | 1 | 49.00 | +-----------------------+-------------+----------+
LIMIT 还能配合偏移量做"翻页":LIMIT 2, 1 表示跳过 2 行取 1 行(MySQL 语法;PostgreSQL 写 LIMIT 1 OFFSET 2)。第 7 章会讲到深翻页的性能陷阱,这里先留个记号。另一个必记细节:ORDER BY 遇到 NULL 时各数据库口径不一,MySQL 把 NULL 排在最前(升序时),PostgreSQL 排最后,跨库迁移时排序结果悄悄不同,排查起来非常隐蔽。
⚠️ 常见坑:没写 ORDER BY 却依赖"上次就是这个顺序"。表的存储顺序没有任何承诺,一旦并发写入、磁盘整理或换了数据库版本,顺序就可能变化。凡是结果对顺序有要求的查询——尤其分页——ORDER BY 一个都不能省。
💡 关键直觉:把每条 SELECT 当成一条流水线来读——FROM 进原料、WHERE 筛次品、SELECT 做加工、ORDER BY 排成品、LIMIT 装箱出货。读得多了,你会在写之前先在脑子里"空跑"一遍。
数据现在还只有寥寥几行。下一节先把练习场真正搭起来:建库、建表、选类型,为全书准备好完整的示例数据。