Search code examples
mysqlsqllimit

Mysql query providing only one (highest rank) per condition


I got a database table with the following data:

id | country | date       | rank   | sport
--------------------------------------------
1  | UK      | 2000-01-30 | 1      | tennis
2  | US      | 2000-01-30 | 2      | tennis
3  | UK      | 2000-01-30 | 3      | tennis
4  | FR      | 2000-01-30 | 4      | tennis
5  | UK      | 2000-01-30 | 5      | tennis
6  | NL      | 2000-01-30 | 6      | tennis
7  | DE      | 2000-01-30 | 1      | golf
8  | ES      | 2000-01-30 | 2      | golf
9  | GR      | 2000-01-30 | 3      | golf
10 | GR      | 2000-01-30 | 4      | golf
11 | ES      | 2000-01-30 | 5      | golf
12 | NL      | 2000-01-30 | 6      | golf
13 | US      | 2000-01-31 | 1      | tennis
14 | FR      | 2000-01-31 | 2      | tennis
15 | UK      | 2000-01-31 | 3      | tennis
16 | UK      | 2000-01-31 | 4      | tennis
17 | FR      | 2000-01-31 | 5      | tennis
18 | BE      | 2000-01-31 | 6      | tennis
19 | DE      | 2000-01-31 | 1      | golf
20 | BE      | 2000-01-31 | 2      | golf
21 | ES      | 2000-01-31 | 3      | golf
22 | US      | 2000-01-31 | 4      | golf
23 | UK      | 2000-01-31 | 5      | golf
24 | NL      | 2000-01-31 | 6      | golf

etc.

Desired output

I'd like to see the following output for a selected country:

  • Average sport rank for this country on the selected date (all sports accounted, but only the highest rank per sport. So, if the UK is listed twice for tennis (position 6 and 7 for example, only the position 6 should be taken))
  • Number of top-6 notations on the selected date for the country (only the highest rank per sport is counted)
  • Number of sports the country is listed for on the selected date

So, for example, the result for the UK should look like this:

UK:

date         |  avg. rank | amount sports in top 6 rank |   sum of highest rank per sport
--------------------------------------------------------------------------------------------
2000-01-30   |  1,0       | 1                           |   1                            
2000-01-31   |  4,0       | 2                           |   8                            

It doesnt seem too difficult, however, I did not managed to get it working.

Tried solution

I use the following mysql query:

SELECT
        date,
        AVG(rank) as avgRank,
        COUNT(rank) as numRank,
        SUM(rank) as sumRank
    FROM `table`
    WHERE
        country='UK'
    GROUP BY date
    ORDER BY
        date,rank ASC

It does almost work, however, I have a little problem. The output looks like:

UK:

date         |  avg. rank (avgRank) | amount sports in top 6 rank (numRank) |   sum of highest rank per sport (sumRank)
--------------------------------------------------------------------------------------------
2000-01-30   |  4,5                 | 3                                     |   9                            
2000-01-31   |  4,0                 | 3                                     |   12   

So, it seems that it counts every notation for UK instead of only the highest rank per day per sport. How do I change the query so it works correctly? I tried to add "sport" to the GROUP BY statement, but that leaves me with the following (one row per sport):

UK:

date         |  avg. rank | amount sports in top 6 rank |   sum of highest rank per sport
--------------------------------------------------------------------------------------------
2000-01-30   |  4,5       | 3                           |   9                                        
2000-01-31   |  3,5       | 2                           |   7   
2000-01-31   |  5,0       | 1                           |   5

Who could help me out? :)


Solution

  • I think this query will give you the results you want. It uses a subquery to find the highest rank per day for each country and sport, then aggregates those outside the subquery:

    SELECT t1.date,
           t1.country,
           AVG(min_rank) AS `avg rank`,
           SUM(min_rank <= 6) AS `num top 6`,
           COUNT(sport) AS `num sports`
    FROM (SELECT `date`, `country`, `sport`,
                  MIN(`rank`) AS min_rank
          FROM `table`
          GROUP BY `date`, `country`, `sport`) t1
    WHERE t1.country = 'UK'
    GROUP BY t1.date, t1.country
    

    Output

    date        country     avg rank    num top 6   num sports
    2000-01-30  UK          1           1           1
    2000-01-31  UK          4           2           2
    

    Demo on dbfiddle