MySQL Forums
Forum List  »  Newbie

Re: SELECT TOP 3 scores in each class with JOIN
Posted by: Peter Brawley
Date: October 04, 2016 05:33PM

?! Repeating multiple post texts obscures more than it clarifies.

A solution, though, needs general rules that could generate it.

One rule I've been missing under your details is:
`score` values are to be evaluated within groups of `class` values

ie this is the Top N Per Group problem.

Indeed your starting query looks a lot like the first (unscalable) solution at http://www.artfulsoftware.com/queries.php under "Within-group quotas (Top N per group)".

For others reading along, given this DDL...

DROP TABLE IF EXISTS test; 
CREATE TABLE test( id INT, entrydate DATE ); 
INSERT INTO test VALUES 
( 1, '2007-5-01' ),( 1, '2007-5-02' ),( 1, '2007-5-03' ),( 1, '2007-5-04' ), 
( 1, '2007-5-05' ),( 1, '2007-5-06' ),( 2, '2007-6-01' ),( 2, '2007-6-02' ), 
( 2, '2007-6-03' ),( 2, '2007-6-04' ),( 3, '2007-7-01' ),( 3, '2007-7-02' ),( 3, '2007-7-03' ); 
{/code]
the Top N Per Group question is, what query gives the earliest two entrydates per ID?
SELECT tmp.ID, tmp.entrydate 
FROM ( 
  SELECT 
    ID, entrydate, 
    IF( @prev <> ID, @rownum := 1, @rownum := @rownum+1 ) AS rank, 
    @prev := ID 
  FROM test t 
  JOIN (SELECT @rownum := NULL, @prev := 0) AS r 
  ORDER BY t.ID 
) AS tmp 
WHERE tmp.rank <= 2 
ORDER BY ID, entrydate;
+------+------------+
| ID   | entrydate  |
+------+------------+
|    1 | 2007-05-01 |
|    1 | 2007-05-02 |
|    2 | 2007-06-03 |
|    2 | 2007-06-04 |
|    3 | 2007-07-01 |
|    3 | 2007-07-02 |
+------+------------+
Touching up this example to get top 3 per class from your hwdata table gives ...
SELECT tmp.class, tmp.rank, entrynum, tmp.score
FROM ( 
  SELECT 
    class, entrynum, score, 
    IF( @prev <> class, @rownum := 1, @rownum := @rownum+1 ) AS rank, 
    @prev := class 
  FROM hwdata d 
  JOIN (SELECT @rownum := NULL, @prev := 0) AS r 
  ORDER BY class, score desc
) AS tmp 
WHERE tmp.rank <= 3 
ORDER BY class, rank;
+-----------------------+------+----------+-------+
| class                 | rank | entrynum | score |
+-----------------------+------+----------+-------+
| FULL SIZE GM 07 - UP  |    1 |        1 |  84.0 |
| FULL SIZE GM 07 - UP  |    2 |        3 |  59.5 |
| FULL SIZE GM 07 - UP  |    3 |        4 |  62.0 |
| FULL SIZE GM 88 to 06 |    1 |        2 |  17.5 |
| FULL SIZE GM 88 to 06 |    2 |        5 |  88.5 |
| FULL SIZE GM 88 to 06 |    3 |        7 |  59.5 |
+-----------------------+------+----------+-------+
A Where clause screws up the counting vars, so your specific exclusion fiddles need to be hidden
from that level, in the definition of the alias `d`.

One could write a complicated Left Join to awards in there, which obviously you're free to do,

But to show the general solution, better for a forum like this, I've just used hwdata columns ...
SELECT tmp.class, tmp.rank, entrynum, tmp.score
FROM ( 
  SELECT 
    d.class, d.entrynum, d.score,
    IF( @prev <> class, @rownum := 1, @rownum := @rownum+1 ) AS rank, 
    @prev := class 
  FROM (SELECT * from hwdata where award NOT LIKE '%Best of%' AND Length(dsqreason)=0) d
  JOIN (SELECT @rownum := NULL, @prev := 0) AS r 
  ORDER BY d.class, score desc 
) AS tmp 
WHERE tmp.rank <= 3 
ORDER BY class, rank;
+-----------------------+------+----------+-------+
| class                 | rank | entrynum | score |
+-----------------------+------+----------+-------+
| FULL SIZE GM 07 - UP  |    1 |        1 |  84.0 |
| FULL SIZE GM 07 - UP  |    2 |        4 |  62.0 |
| FULL SIZE GM 07 - UP  |    3 |        6 |  61.0 |
| FULL SIZE GM 88 to 06 |    1 |        8 |  65.0 |
| FULL SIZE GM 88 to 06 |    2 |        7 |  59.5 |
+-----------------------+------+----------+-------+
If there are more fiddles, you can see where to add them.

Options: ReplyQuote


Subject
Written By
Posted
Re: SELECT TOP 3 scores in each class with JOIN
October 04, 2016 05:33PM


Sorry, you can't reply to this topic. It has been closed.

Content reproduced on this site is the property of the respective copyright holders. It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.