我在使用特定的MySQL查询时非常困难。 这是我需要连接的3个表的结构,并从以下行开始排序:
users
ID username
routes
ID val_1 val_2 val_3 val_4
scores
ID route_id user_id route_level
此查询用于排行榜功能,需要返回按其最佳分数排序的用户ID列表。一个用户可能有几个分数,我们需要找到最佳分数。
扭曲是“route_level”部分:如果此列的值是例如“2”,那么我们需要转到相应的route_id,并找到val_1和val_2之间的最大值。我们必须不高于val_x,x是列得分的值.route_level。
此外,val_x不是int(值通常类似于“6A +”,下一个更大的值是6B,然后是6B +等),而val_x不一定小于val_x + 1.
这是我得到的,但它不起作用(我得到的结果遍布整个地方,根本没有订购,至少不是我能理解的方式):
SELECT u.*, r.val_1 AS v1, r.val_2 AS v2, r.val_3 AS v3, r.val_4 AS v4
FROM users u
INNER JOIN scores s
ON s.user_id = u.ID
INNER JOIN routes r
ON s.route_id = r.ID
GROUP BY u.ID
ORDER BY GREATEST(v1, v2, v3, v4) DESC
你们有没有想过如何在一个MySQL查询中使用它?
谢谢! : - )
编辑:这是SQLFiddle link
答案 0 :(得分:0)
您需要获得正确的汇总查询才能使您的订购正确。试试这个。它将正确处理用户的聚合,并为每个用户提取最大val_n
分数。
SELECT u.ID, u.username,
MAX(r.val_1) AS v1,
MAX(r.val_2) AS v2,
MAX(r.val_3) AS v3,
MAX(r.val_4) AS v4
FROM users u
INNER JOIN scores s ON s.user_id = u.ID
INNER JOIN routes r ON s.route_id = r.ID
GROUP BY u.ID ,u.username
ORDER BY GREATEST( MAX(r.val_1), MAX(r.val_2), MAX(r.val_3), MAX(r.val_4)) DESC
编辑我错过了关于route_level的一些内容...过分关注问题中的查询,而不是文本。
但它并不是很难应用。它需要在详细级别逐行应用,在聚合函数MAX()
之前。我相信,可以通过更改查询的SELECT
部分来完成此操作。
SELECT u.ID, u.username,
MAX(GREATEST (
IF(r.route_level>=1, r.val_1, NULL)
IF(r.route_level>=2, r.val_2, NULL)
IF(r.route_level>=3, r.val_3, NULL)
IF(r.route_level>=4, r.val_4, NULL) )) AS val
FROM users u
INNER JOIN scores s ON s.user_id = u.ID
INNER JOIN routes r ON s.route_id = r.ID
GROUP BY u.ID ,u.username
ORDER BY MAX(GREATEST (
IF(r.route_level>=1, r.val_1, NULL)
IF(r.route_level>=2, r.val_2, NULL)
IF(r.route_level>=3, r.val_3, NULL)
IF(r.route_level>=4, r.val_4, NULL) ))
我也错过了关于val_n
值为varchar()
值而不是整数的观点。那个更难。在MAX()
值上使用varchar()
时,它会使用排序规则。我知道的所有字符排序规则都会声明值6B+
例如大于10B+
,因为6
大于1
。
对不起,我不知道任何优雅的SQL魔法可以让它更好地工作。
答案 1 :(得分:0)
你看起来真的很近......
但是你需要一个聚合函数来获得“最佳分数”。 (除了MySQL以外的数据库会反对你的陈述,抓住对未包含在GROUP BY中的非聚合的引用...)
关于route_level
的“扭曲”有点棘手。我先处理,从每一行得到“最好”的分数。我会使用这样的表达式:
IF(r.route_level>=1,r.val_1,NULL)
IF(r.route_level>=2,r.val_2,NULL)
IF(r.route_level>=3,r.val_3,NULL)
IF(r.route_level>=4,r.val_4,NULL)
这些表达式有条件地从特定val_N
列返回一个值,具体取决于route_level
的值。由于您不需要返回单个值,因此可以将所有这些表达式包装在方便的GREATEST()
函数中。
GREATEST( IF(r.route_level>=1,r.val_1,NULL)
, IF(r.route_level>=2,r.val_2,NULL)
, IF(r.route_level>=3,r.val_3,NULL)
, IF(r.route_level>=4,r.val_4,NULL)
, ...
)
这将从每一行获得“最佳分数”。现在剩下的就是从给定用户返回的多行中找到“最佳分数”。我们可以使用MAX聚合来做到这一点。
因此,您需要对查询进行的唯一更改是替换ORDER BY子句中的表达式。像这样:
SELECT u.ID
FROM users u
JOIN scores s
ON s.user_id = u.ID
JOIN routes r
ON s.route_id = r.ID
GROUP BY u.ID
ORDER BY MAX( GREATEST( IF(r.route_level>=1,r.val_1,NULL)
, IF(r.route_level>=2,r.val_2,NULL)
, IF(r.route_level>=3,r.val_3,NULL)
, IF(r.route_level>=4,r.val_4,NULL)
)
) DESC
(同样从SELECT列表中删除所有那些val_1,val_2等表达式。不确定哪些行将返回。这些值中没有一个可能是“最佳分数”。如果你还想返回“最佳得分”的值,然后在SELECT列表的ORDER BY中使用相同的表达式。
答案 2 :(得分:0)
结合Ollie Jones和spencer7593的答案,我找到了自己问题的答案:
SELECT u.ID, u.username, s.route_level,
GREATEST( IF(s.route_level >= 1, MAX(r.val_1), 0)
, IF(s.route_level >= 2, MAX(r.val_2), 0)
, IF(s.route_level >= 3, MAX(r.val_3), 0)
, IF(s.route_level >= 4, MAX(r.val_4), 0)
) AS vmax
FROM users u
INNER JOIN scores s ON s.user_id = u.ID
INNER JOIN routes r ON s.route_id = r.ID
GROUP BY u.ID
ORDER BY vmax DESC
这给出了最大值AS vmax,考虑了每行的route_length值,并正确排序结果。
感谢大家的参与! : - )