繁体   English   中英

没有联接的SQL筛选器行

[英]SQL filter rows without join

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

是否可以在不加入表格的情况下获得真实的结果? 如何实现呢?

您可以使用变量:

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记录是team score最高的记录。

在这里演示

您可以通过使用子查询来执行以下操作而无需联接:

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

尽管联接本身非常昂贵,但是无论表中有多少行,这种方式都只需要运行两个实际查询。 因此,在大表中,此方法仍可以比第一种带有子查询的方法快数百倍(甚至数千倍)。

不幸的是,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解决方案之类的变量来完成。

您可以执行以下操作:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM