我有一个包含表的数据库:
任务:
PK Name
PK qName
goal
Run Code Online (Sandbox Code Playgroud)公会:
PK Name
PK gName
level
Run Code Online (Sandbox Code Playgroud)游戏:
PK Name
MaxPlayer
levels
uName
Run Code Online (Sandbox Code Playgroud)公会任务:
PK Name
PK gName
PK qName
Run Code Online (Sandbox Code Playgroud)我需要检索包含最多公会的游戏的名称。
公会由游戏分配。
我尝试的查询:
SELECT Name, Count(*) guildName
FROM Game game, Guild guild
WHERE game.Name = Guild.gName
Run Code Online (Sandbox Code Playgroud)
并以某种方式使用 MAX 函数。
我有点困惑如何执行此操作,非常感谢任何帮助。
一个明显的解决方案是获取所有计数,按降序对它们进行排序并仅检索最上面的行:
SELECT
gName,
COUNT(Name) AS GuildCount
FROM
Guild
GROUP BY
gName
ORDER BY
GuildCount DESC
LIMIT
0, 1
;
Run Code Online (Sandbox Code Playgroud)
这仅适用于只有一个游戏可以拥有最大数量的情况,但您可能无法保证这一点。所以上面的解决方案不是很好,因为如果两个或更多游戏具有相同的最高数字,你会说你想要获得所有这些名字。
所以,你可以试试这种方法:
SELECT
gName,
COUNT(Name) AS GuildCount
FROM
Guild
GROUP BY
gName
HAVING
COUNT(Name) =
(
SELECT
COUNT(Name)
FROM
Guild
GROUP BY
gName
ORDER BY
GuildCount DESC
LIMIT
0, 1
)
;
Run Code Online (Sandbox Code Playgroud)
子查询将只获取公会数量和最高公会数量,而外部查询将获取那些具有匹配公会数量的游戏的名称。
上面的问题显然是你必须扫描表两次,每次执行相同的分组,而且分组本身也必须在代码中重复。问题是,如何避免这种情况?
现在,其他 SQL 平台提供强大的工具(如排名函数),而 MySQL 正试图通过允许您使用变量来实现更好的性能来弥补。在这种情况下,也可以使用变量一次性获得结果并避免逻辑重复。这是一种方法:
SELECT
gName,
GuildCount
FROM
(
SELECT
IF(@LastCount <> 0 AND @LastCount <> grp.GuildCount, @flag := 0, @flag) AS flag,
grp.gName,
@LastCount := grp.GuildCount AS GuildCount
FROM
(
SELECT
@LastCount := 0,
@flag := 1
) AS init,
(
SELECT
gName,
COUNT(Name) AS GuildCount
FROM
Guild
GROUP BY
gName
ORDER BY
GuildCount DESC
) AS grp
) AS derived
WHERE
flag = 1
;
Run Code Online (Sandbox Code Playgroud)
该init
派生表仅仅是变量初始化,并grp
提供了初始设定值合计的从高到低的顺序来使用我们的变量进行排序。
逻辑的主要部分位于实际使用变量的第二个嵌套级别。该@flag
变量用于生成flag
用于进一步过滤的列,用 标记需要包含在输出中的行,1
其余的用标记0
。它最初设置为 1,因为显然需要包括第一行。一旦遇到小于最大值的数字,它就会重置为 0。为此,使用了另一个变量@LastCount
, 来存储前一行的计数值。
最外层查询仅过滤flag
列上的嵌套集。
该解决方案可以在 Rexester进行测试。