Show top N rows by category in MySQL 8 without duplicates in another category

别说谁变了你拦得住时间么 提交于 2019-12-11 08:04:01

问题


Similar to this question, I have the following table in MySQL 8.0.15:

CREATE TABLE golf_scores (id INT PRIMARY KEY AUTO_INCREMENT, person TEXT, score INT, age INT);
INSERT INTO golf_scores (person, score, age) VALUES ('Angela', 40, 25),('Angela', 45, 25),('Angela', 55, 25),('Peter',45, 32),('Peter',55,32),('Rachel', 65, 35),('Rachel',75,35),('Jeff',75, 16);
SELECT * FROM golf_scores;
+----+--------+-------+------+
| id | person | score | age  |
+----+--------+-------+------+
|  1 | Angela |    40 |   25 |
|  2 | Angela |    45 |   25 |
|  3 | Angela |    55 |   25 |
|  4 | Peter  |    45 |   32 |
|  5 | Peter  |    55 |   32 |
|  6 | Rachel |    65 |   35 |
|  7 | Rachel |    75 |   35 |
|  8 | Jeff   |    75 |   16 |
+----+--------+-------+------+

We want to select the following "best" 3 rows:

+----+--------+-------+------+
| id | person | score | age  |
+----+--------+-------+------+
|  1 | Angela |    40 |   25 |
|  4 | Peter  |    45 |   32 |
|  6 | Rachel |    65 |   35 |
+----+--------+-------+------+

In other words, the lowest 3 golf scores without having duplicates by person, and also the other columns from that row. I'm not worried about ties; I'd still just like three results.

The query SELECT person, MIN(score) as min_score FROM golf_scores GROUP BY person ORDER BY min_score LIMIT 3; gives the right rows, but is limited to the columns person and score`. When I try to modify it like this:

SELECT id, person, MIN(score) as min_score, age FROM golf_scores GROUP BY person ORDER BY min_score LIMIT 3;

I get this error:

ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'records.golf_scores.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

I also tried eliminating duplicate names with SELECT id, DISTINCT person, score, age FROM golf_scores ORDER BY score LIMIT 3 but I get an error

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DISTINCT person, score FROM golf_scores ORDER BY score LIMIT 3' at line 1

How can I get the desired output in MySQL?


回答1:


Use row_number():

select t.*
from (select t.*, row_number() over (partition by person order by score) as seqnum
      from golf_scores  t
     ) t
where seqnum = 1
order by score asc
limit 3;

In older versions, you can do this by using a correlated subquery and id:

select gs.*
from golf_scores gs
where gs.id = (select gs2.id
               from golf_scores gs2
               where gs2.person = gs.person
               order by gs2.score asc
               limit 1
              )
order by score asc
limit 3;

This may also be the fastest way with an index on golf_scores(person, score, id).




回答2:


Here's one way:

SELECT x.* 
  FROM golf_scores x
  JOIN 
     ( SELECT MIN(id) id FROM
            ( SELECT a.* 
                FROM golf_scores a 
                JOIN 
                   ( SELECT person, MIN(score) score FROM golf_scores GROUP BY person ) b 
                  ON b.person = a.person 
                 AND b.score = a.score 
            ) n
        GROUP
           BY person
            , score 
     ) y
    ON y.id = x.id
 ORDER 
    BY x.score LIMIT 3;


来源:https://stackoverflow.com/questions/54710377/show-top-n-rows-by-category-in-mysql-8-without-duplicates-in-another-category

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!