首页 > 解决方案 > 正确替换 MySQL 服务器中的循环

问题描述

我有这张桌子:

在此处输入图像描述

我想找到每个年龄段出现最多的级别,例如 18 岁出现最多的级别是“FR”,而 19 岁是“SO”。

我的尝试:

SELECT X.AGE, X.LEVEL FROM 
( SELECT S.AGE, S.LEVEL FROM STUDENT S WHERE S.AGE = 18) AS X 
GROUP BY X.LEVEL 
ORDER BY COUNT(*) DESC LIMIT 1;

我得到这个结果:

在此处输入图像描述

SELECT DISTINCT S.AGE FROM STUDENT S;如何在知道我被阻止使用 while 循环的情况下迭代他们在此列表中的所有不同年龄。

标签: mysql

解决方案


在 MySQL 8.0 之前,您必须使用自连接。

首先,您使用计数提取年龄和级别。

SELECT AGE, LEVEL, COUNT(*) AS C FROM STUDENT GROUP BY AGE, LEVEL

这让你说,

18 FR 2
18 SR 5
18 XX 5
19 FR 1

从中,您选择每个年龄的最大值 - 但您只想要一行,并且当年龄为 18 时,SR 和 XX 的最大值都为 5。否则,您可以使用自联接,首先选择"18 5" 使用 MAX() 然后再次加入以获得对应于 (18, 5) 的 LEVEL —— 仅,这里有两个级别可以匹配。当然你可以使用另一个 MAX。

SELECT A1.AGE, MAX(A2.LEVEL) FROM
  ( SELECT AGE, MAX(C) AS M FROM ( the query above ) AS A0 GROUP BY AGE ) AS A1
  JOIN
  ( SELECT AGE, MAX(C) AS M FROM ( the query above ) AS A0 GROUP BY AGE ) AS A2
ON (A1.AGE = A2.AGE AND A1.M = A2.M)

或者您可以使用 hack 来限制子查询和自联接的数量:

SELECT AGE, SUBSTRING_INDEX(MAX(CONCAT(LPAD(C, 5, '0'), ':', LEVEL), ':', -1)) AS LEVEL FROM (
    SELECT AGE, LEVEL, COUNT(*) AS C FROM STUDENT GROUP BY AGE, LEVEL
) AS INT GROUP BY AGE

该复杂表达式将首先将数字和级别连接到一个字符串中,以便“1 FR”和“15 SR”变为“00001:FR”和“00015:SR”,从而允许按字典顺序进行比较。然后 MAX 会按字母顺序提取最大值,现在也和数字顺序一样,数字相等时使用 LEVEL。所以你现在会得到

18   00005:XX

最后 SUBSTRING_INDEX 将采用字符串的最后一个元素,以冒号分隔,因此是所需的“XX”值。


推荐阅读