3.6.4 拥有某个字段的组间最大值的行

任务: 对每个物品, 找出最贵价格物品的经销商.

这个问题可以通过这样的子查询来解决:

  1. SELECT article, dealer, price
  2. FROM shop s1
  3. WHERE price=(SELECT MAX(s2.price)
  4. FROM shop s2
  5. WHERE s1.article = s2.article)
  6. ORDER BY article;
  7. +---------+--------+-------+
  8. | article | dealer | price |
  9. +---------+--------+-------+
  10. | 0001 | B | 3.99 |
  11. | 0002 | A | 10.99 |
  12. | 0003 | C | 1.69 |
  13. | 0004 | D | 19.95 |
  14. +---------+--------+-------+

前面的例子使用了关联子查询, 这可能是低效的(参阅 Section 13.2.11.7, “关联子查询”). 解决此问题的其它可能性是在 FROM 子句中使用不相关的子查询, LEFT JOIN, 或者带有窗口函数的公共表表达式.

非关联子查询:

  1. SELECT s1.article, dealer, s1.price
  2. FROM shop s1
  3. JOIN (
  4. SELECT article, MAX(price) AS price
  5. FROM shop
  6. GROUP BY article) AS s2
  7. ON s1.article = s2.article AND s1.price = s2.price
  8. ORDER BY article;

LEFT JOIN:

  1. SELECT s1.article, s1.dealer, s1.price
  2. FROM shop s1
  3. LEFT JOIN shop s2 ON s1.article = s2.article AND s1.price < s2.price
  4. WHERE s2.article IS NULL
  5. ORDER BY s1.article;

LEFT JOIN 的基本工作原理是当 s1.price 处于最高值时, 并没有 s2.price 对应 s2.article 的值为 NULL. 参阅 Section 13.2.10.2, “JOIN 语法”.

使用窗口函数的公共表表达式:

  1. WITH s1 AS (
  2. SELECT article, dealer, price,
  3. RANK() OVER (PARTITION BY article
  4. ORDER BY price DESC
  5. ) AS `Rank`
  6. FROM shop
  7. )
  8. SELECT article, dealer, price
  9. FROM s1
  10. WHERE `Rank` = 1
  11. ORDER BY article;