MYSQL - Group by limit

前端 未结 3 1834
太阳男子
太阳男子 2020-12-06 16:48

Is there a simple way to LIMIT the GROUP BY results to the top 2. The following query returns all the results. Using \'LIMIT 2\' reduces the overall list to the top 2 entr

3条回答
  •  刺人心
    刺人心 (楼主)
    2020-12-06 17:35

    This is still possible via a single query, but it's a bit long, and there are some caveats, which I'll explain after the query. Though, they're not flaws in the query so much as some ambiguity in what "top two" means.

    Here's the query:

    SELECT ratings.* FROM
    (SELECT rating_name, 
           id_markets, 
           sum(rating_good) 'good', 
           sum(rating_neutral)'neutral', 
           sum(rating_bad) 'bad' 
     FROM zzratings 
     WHERE rating_year=year(curdate()) AND rating_week = week(curdate(),1)
     GROUP BY rating_name,id_markets) AS ratings
    LEFT JOIN
    (SELECT rating_name, 
           id_markets, 
           sum(rating_good) 'good', 
           sum(rating_neutral)'neutral', 
           sum(rating_bad) 'bad' 
     FROM zzratings 
     WHERE rating_year=year(curdate()) AND rating_week= week(curdate(),1)
     GROUP BY rating_name,id_markets) AS ratings2
    ON ratings2.good <= ratings.good AND
      ratings2.id_markets <> ratings.id_markets AND
      ratings2.rating_name = ratings.rating_name
    LEFT JOIN
    (SELECT rating_name, 
           id_markets, 
           sum(rating_good) 'good', 
           sum(rating_neutral)'neutral', 
           sum(rating_bad) 'bad' 
     FROM zzratings 
     WHERE rating_year=year(curdate()) AND rating_week= week(curdate(),1)
     GROUP BY rating_name,id_markets) AS ratings3
    ON ratings3.good >= ratings2.good AND
      ratings3.id_markets <> ratings.id_markets AND
      ratings3.id_markets <> ratings2.id_markets AND
      ratings3.rating_name = ratings.rating_name
    WHERE (ratings2.good IS NULL OR ratings3.good IS NULL) AND
      ratings.good IS NOT NULL
    ORDER BY ratings.rating_name, ratings.good DESC
    

    The caveat is that if there is more than one id_market with the same "good" count for the same rating_name, then you will get more than two records. For example, if there are three ireland id_markets with a "good" count of 3, the highest, then how can you display the top two? You can't. So the query will show all three.

    Also, if there were one count of "3", the highest, and two counts of "2", you couldn't show the top two, since you have a tie for second place, so the query shows all three.

    The query will be simpler if you create a temporary table with the aggregate result set first, then work from that.

    CREATE TEMPORARY TABLE temp_table
      SELECT rating_name, 
               id_markets, 
               sum(rating_good) 'good', 
               sum(rating_neutral)'neutral', 
               sum(rating_bad) 'bad' 
         FROM zzratings 
         WHERE rating_year=year(curdate()) AND rating_week= week(curdate(),1;
    
    SELECT ratings.*
     FROM temp_table ratings
    LEFT JOIN temp_table ratings2
    ON ratings2.good <= ratings.good AND
      ratings2.id_markets <> ratings.id_markets AND
      ratings2.rating_name = ratings.rating_name
    LEFT JOIN temp_table ratings3
    ON ratings3.good >= ratings2.good AND
      ratings3.id_markets <> ratings.id_markets AND
      ratings3.id_markets <> ratings2.id_markets AND
      ratings3.rating_name = ratings.rating_name
    WHERE (ratings2.good IS NULL OR ratings3.good IS NULL) AND
      ratings.good IS NOT NULL
    ORDER BY ratings.rating_name, ratings.good DESC;
    

提交回复
热议问题