没有连接的SQL过滤器行

时间:2016-06-09 10:11:27

标签: mysql sql

我总是因为不必要的加入而“烦恼”。但在这种情况下,我想知道是否可以不使用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分的球员,所以结果没有一致性。

如果不加入桌子,是否有可能获得真实的结果?如何实现?

4 个答案:

答案 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值最大的记录。

Demo here

答案 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