Kodewick
第 10 课,共 21 课目录

查询的执行顺序

第 10 课,共 21 课 · 第 2 部分 · 汇总 · 约 15 分钟

前几课的子句凑在一起,一条查询可以很长。先看一条把它们全用上的:

main.sql
1SELECT category,2    COUNT(*) AS product_count,3    ROUND(AVG(price), 2) AS avg_price4FROM products5WHERE stock > 06GROUP BY category7HAVING SUM(stock) >= 508ORDER BY avg_price DESC9LIMIT 2;
输出
categoryproduct_countavg_price
数码327.50
厨房210.95
2 行

意思是:有货的商品按分类分组,只看库存加起来至少 50 的分类,按平均价从高到低,取前 2 个。

我们写的时候 SELECT 在最前面,可数据库做的时候,SELECT 几乎排在最后。

真正的顺序

数据库照这个顺序一步一步做,每一步都拿上一步的结果接着做:

  1. FROM:拿到 products 表,10 行。
  2. WHERE:一行一行看,台灯库存是 0,删掉,剩 9 行。
  3. GROUP BY:按分类分成 4 组。
  4. HAVING:箱包的库存加起来只有 40,整组删掉,剩 3 组。
  5. SELECT:每组算出 category、product_count、avg_price,别名在这时才起好。
  6. ORDER BY:按 avg_price 从高到低排。
  7. LIMIT:只留前 2 行。

点上面那段的单步,把这 7 步一步一步走一遍,看每一步之后表变成了什么样。

没写的子句就跳过。最短的查询只有 FROM 和 SELECT 两步。

WHERE 里用不了别名

记住这个顺序,很多报错就说得通了。算每件商品的库存值(价格 × 库存),只要超过 500 的:

main.sql
1SELECT name, price * stock AS stock_value2FROM products3WHERE stock_value > 500;
输出
ERROR 1054 (42S22): Unknown column 'stock_value' in 'where clause'

没有叫「stock_value」的列(WHERE 里不能用 SELECT 里起的别名)。检查一下列名有没有写错;如果它是一段文字,要加引号:'stock_value'。

ERROR 1054:不认识 stock_value。WHERE 是第 2 步,起别名的 SELECT 是第 5 步,做 WHERE 的时候这个名字还不存在。

在 WHERE 里把算式再写一遍就好:

main.sql
1SELECT name, price * stock AS stock_value2FROM products3WHERE price * stock > 5004ORDER BY stock_value DESC;
输出
namestock_value
数据线1700.00
双肩包598.50
咖啡杯594.00
耳机590.00
笔记本540.00
手机壳525.00
6 行

ORDER BY 里可以

上面那段的 ORDER BY stock_value DESC 没报错:ORDER BY 是第 6 步,在 SELECT 之后,别名已经有了。分组的查询也一样:

main.sql
1SELECT customer_id, COUNT(*) AS order_count2FROM orders3GROUP BY customer_id4ORDER BY order_count DESC, customer_id5LIMIT 3;
输出
customer_idorder_count
13
22
42
3 行
先猜一猜

运行会怎样?

1SELECT name, price AS p2FROM products3WHERE p < 104ORDER BY p;

聚合在哪一步算

顺序也说明了第 9 课的 ERROR 1111:聚合函数要等第 3 步分完组才算得出来,第 2 步的 WHERE 用不上;第 4 步的 HAVING 和后面的 SELECT、ORDER BY 都可以用。所以按一组的结果排序,直接写聚合函数也行:

main.sql
1SELECT category, SUM(stock) AS total_stock2FROM products3GROUP BY category4ORDER BY SUM(stock) DESC;
输出
categorytotal_stock
数码245
文具200
厨房100
箱包40
4 行

小技巧: MySQL 比较宽松,GROUP BY 和 HAVING 里也认 SELECT 的别名。别的数据库很多不认。要到哪儿都能用,记住标准的规矩:别名只在 ORDER BY 里用。

LIMIT 最后做

LIMIT 是最后一步,在排好序之后才截。所以「最贵的 3 件」这样写是对的:先按价格从高到低排好,再取前 3 行。

main.sql
1SELECT name, price2FROM products3ORDER BY price DESC4LIMIT 3;
输出
nameprice
耳机59.00
双肩包39.90
台灯25.00
3 行

要是先截再排,取到的只是表里碰巧在前面的 3 行,那就不是「最贵的 3 件」了。

子句的书写顺序

做的顺序是一回事,写的顺序是固定的另一回事,不能随便调换:

SELECT … FROM … WHERE … GROUP BY … HAVING … ORDER BY … LIMIT …

写错位置,比如把 WHERE 写在 GROUP BY 后面,就会得到 ERROR 1064:语法错误。下面第 3 题就是这样。

练一练

写好查询,点检查。提示随便看,实在想不出来再看答案。

练习 1

修好它:别名

想查出金额(quantity * unit_price)至少 30 的明细行,却报了 ERROR 1054。改好它,列是 order_id 和 amount,按 amount 从大到小,一样的按 order_id 排。

要显示
order_idamount
359.00
859.00
239.90
739.90
1239.60
5 行
exercise1.sql
1SELECT order_id, quantity * unit_price AS amount2FROM order_items3WHERE amount >= 304ORDER BY amount DESC, order_id;
输出
点「运行」或按 Ctrl+Enter
练习 2

便宜货卖得最好的

从 order_items 里,只看单价低于 20 的明细,按商品分组,算出每件商品卖了几件;只留卖了至少 3 件的,按件数从多到少(一样的按 product_id),取前 3 个。列是 product_id 和 sold。

要显示
product_idsold
110
86
23
3 行
exercise2.sql
1SELECT product_id, quantity, unit_price FROM order_items;
输出
点「运行」或按 Ctrl+Enter
练习 3

修好它:顺序

想数一数每个分类里价格超过 10 的商品有几件,却报了 ERROR 1064。改好它,列是 category 和 COUNT(*),按 category 排序。

要显示
categoryCOUNT(*)
厨房1
数码3
箱包2
3 行
exercise3.sql
1SELECT category, COUNT(*)2FROM products3GROUP BY category4WHERE price > 105ORDER BY category;
输出
点「运行」或按 Ctrl+Enter

这一课学会了

  • 执行顺序:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT。
  • 书写顺序是固定的:SELECT、FROM、WHERE、GROUP BY、HAVING、ORDER BY、LIMIT,写错位置是 ERROR 1064。
  • SELECT 的别名在 WHERE 里还不存在(ERROR 1054),在 ORDER BY 里可以用。
  • 聚合函数在分组之后才有,所以 WHERE 里不能用,HAVING、SELECT、ORDER BY 里可以。
  • LIMIT 最后做:先排好序再截。