Query to rank rows in groups

前端 未结 3 846
既然无缘
既然无缘 2021-01-20 10:57

I\'m using Apache Derby 10.10.

I have a list of participants and would like to calculate their rank in their country, like this:

|        Country |           


        
相关标签:
3条回答
  • 2021-01-20 11:30

    Consider a non-windows function SQL query that uses a correlated aggregate count subquery. Because the group column (Country.name) is not in same table as the rank criteria (Participant.points), we need to run same joins in the subquery but rename table aliases to properly compare inner and outer queries.

    Now of course, in a perfect world that would be it but we must now account for tied points. Therefore, another very similar subquery (for tie breaker) is used to be added to first subquery. This second nested query matches inner and outer query's Country.name and Participant.points but ranks by alphabetical order of Participant.name.

    SELECT
        Country.name AS Country,
        Participant.name AS Participant,
        Participant.points,
        (SELECT Count(*) + 1
           FROM Country subC
          INNER JOIN Team subT
                  ON subC.id = subT.country_id
          INNER JOIN Participant subP
                  ON subT.id = subP.team_id
          WHERE subC.name = Country.name
            AND subP.points < Participant.points) 
    
         +
    
        (SELECT Count(*)
           FROM Country subC
          INNER JOIN Team subT
                  ON subC.id = subT.country_id
          INNER JOIN Participant subP
                  ON subT.id = subP.team_id
          WHERE subC.name = Country.name
            AND subP.points = Participant.points
            AND subP.name < Participant.name)  As country_rank
    
    FROM Country
    INNER JOIN Team
            ON Country.id = Team.country_id
    INNER JOIN Participant
            ON Team.id = Participant.team_id
    ORDER BY Country.name, Participant.points;
    
    0 讨论(0)
  • 2021-01-20 11:36

    SQL

    SELECT c.name AS Country,
           p.name AS Participant,
           p.points AS Points,
           (SELECT COUNT(*)
            FROM Participant p2
            JOIN Team t2 ON p2.team_id = t2.id
            WHERE t2.country_id = t.country_id
              AND (p2.points < p.points
                   OR p2.points = p.points AND p2.name <= p.name)) AS country_rank
    FROM Country c
    JOIN Team t ON c.id = t.country_id
    JOIN Participant p ON t.id = p.team_id
    ORDER BY c.name, p.points, p.name;
    

    Online Demo

    SQL Fiddle demo: http://sqlfiddle.com/#!5/f48f8/14

    Explanation

    A simple ANSI-SQL subselect can be used to do the same job, counting the number of records for participants in the same country with a lower score or with the same score and a name that is alphabetically no higher.

    0 讨论(0)
  • 2021-01-20 11:53

    all you need to add is a partition by country and that should give you what you need.

    SELECT
    Country.name,
    Participant.name,
    Participant.points,
    ROW_NUMBER() OVER(PARTITION BY country order by Country.name, Participant.points) as country_rank
    from Country
    join Team
      on Country.id = Team.country_id
    join Participant
      on Team.id = Participant.team_id;
    
    0 讨论(0)
提交回复
热议问题