我总是因为不必要的加入而“烦恼”。但在这种情况下,我想知道是否可以不使用join。
这是我所拥有的表的一个例子:
id | team | score
1 | 1 | 300
2 | 1 | 257
3 | 2 | 127
4 | 2 | 533
5 | 3 | 459
这就是我想要的:
team | score | id
1 | 300 | 1
2 | 533 | 4
3 | 459 | 5
执行如下查询: (基本上:谁是每支球队中最好的球员)
SELECT team, MAX(score) AS score, id
FROM my_table
GROUP BY team
但我得到类似的东西:
team | score | id
1 | 300 | 1
2 | 533 | 3
3 | 459 | 5
但这并不是第三位获得533分的球员,所以结果没有一致性。
如果不加入桌子,是否有可能获得真实的结果?如何实现?
答案 0 :(得分:2)
您可以使用变量:
SELECT id, team, score
FROM (
SELECT id, team, score,
@seq := IF(@t = team, @seq,
IF(@t := team, @seq + 1, @seq + 1)) AS seq,
@grp := IF(@t2 = team, @grp + 1,
IF(@t2 := team, 1, 1)) AS grp
FROM mytable
CROSS JOIN (SELECT @seq := 0, @t := 0, @grp := 0, @t2 := 0) AS vars
ORDER BY score DESC) AS t
WHERE seq <= 3 AND grp = 1
每次满足新团队时,变量@seq
会递增,因为正在按降序score
顺序处理记录。变量@grp
用于枚举每个team
分区中的记录。 @grp = 1
的记录是score
切片中team
值最大的记录。
答案 1 :(得分:2)
你可以使用这样的子查询在没有连接的情况下完成它:
SELECT id, team, score
FROM table1 a
WHERE score = (SELECT MAX(score) FROM table1 b WHERE a.team = b.team);
然而,在大表中,这可能非常慢,因为您必须为表中的每一行运行整个子查询。
然而,使用join来过滤结果并没有错:
SELECT id, team, score FROM table1 a
INNER JOIN (
SELECT MAX(score) score, team
FROM table1
GROUP BY team
) b ON a.score = b.score AND a.team = b.team
尽管加入本身非常昂贵,但这样您只需运行两个实际查询,无论表中有多少行。所以在大表中,这个方法仍然可以比使用子查询的第一个方法快数百,甚至数千倍。
答案 2 :(得分:1)
不幸的是,MySQL不支持像ROW_NUMBER()
这样的窗口函数,它可以很容易地解决这个问题。
有几种方法可以做到这一点:
NOT EXISTS()
:
SELECT * FROM YourTable t
WHERE NOT EXISTS(SELECT 1 FROM YourTable s
WHERE t.team = s.team AND s.score > t.score)
NOT IN()
:
SELECT * FROM YourTable t
WHERE (t.team,t.score) IN(SELECT s.team,MAX(s.score)
FROM YourTable s
GROUP BY s.team)
相关查询:
SELECT distinct t.id,t.team,
(SELECT s.score FROM YourTable s
WHERE s.team = t.team
ORDER BY s.score DESC
LIMIT 1)
FROM YourTable t
或者我理解你已经拥有的联接。
编辑:我接受了我的话,你可以使用像@GiorgosBetsos解决方案那样的变量。
答案 3 :(得分:1)
你可以这样做:
SELECT team, score, id
FROM (SELECT *
,RANK() OVER
(PARTITION BY team ORDER BY score DESC) AS Rank
FROM my_table) ranked_result
WHERE Rank = 1;
有关排名功能的一些信息:Clicketyclickclick