Select highest 3 scores in each day for every user

后端 未结 2 1406
清歌不尽
清歌不尽 2021-01-07 02:28

I have a MYSQL table like this:

  id |  userid  |  score  |      datestamp      |
-----------------------------------------------------
  1  |    1     |   5         


        
2条回答
  •  离开以前
    2021-01-07 03:10

    Please take a look at the following code, if your answer to my comment is yes :) Since your data all in 2012, and month of november, I took day.

    • SQLFIDDLE sample

    Query:

    select y.id, y.userid, y.score, y.datestamp 
    from (select id, userid, score, datestamp 
          from scores
          group by day(datestamp)) as y    
    where (select count(*) 
           from (select id, userid, score, datestamp
                 from scores group by day(datestamp)) as x
           where y.score >= x.score
           and y.userid = x.userid
          ) =1 -- Top 3rd, 2nd, 1st    
    order by y.score desc
    ;
    

    Results:

    ID  USERID  SCORE   DATESTAMP
    8   2       8.5 December, 07 2012 00:00:00+0000
    20  3       6   December, 08 2012 00:00:00+0000
    1   1       5   December, 06 2012 00:00:00+0000
    

    Based on your latter updates to question. If you need some per user by year/month/day and then find highest, you may simply add aggregation function like sum to the above query. I am reapeating myself, since your sample data is for just one year, there's no point group by year or month. That's why I took day.

    select y.id, y.userid, y.score, y.datestamp 
    from (select id, userid, sum(score) as score,
          datestamp 
    from scores
    group by userid, day(datestamp)) as y    
    where (select count(*) 
    from (select id, userid, sum(score) as score
          , datestamp
    from scores
    group by userid, day(datestamp)) as x
    where y.score >= x.score
    and y.userid = x.userid
    ) =1 -- Top 3rd, 2nd, 1st    
    order by y.score desc
    ;
    

    Results based on sum:

    ID  USERID  SCORE   DATESTAMP
    1   1       47.5    December, 06 2012 00:00:00+0000
    8   2       16      December, 07 2012 00:00:00+0000
    20  3       6       December, 08 2012 00:00:00+0000
    

    UPDATED WITH NEW SOURCE DATA SAMPLE

    Simon, please take a look at my own sample. As your data was changing, I used mine. Here is the reference. I have used pure ansi style without any over partition or dense_rank. Also note the data I used are getting top 2 not top 3 scores. You can change is accordingly.

    Guess what, the answer is 10 times simpler than the first impression your first data gave....

    SQLFIDDLE

    Query to 1: -- for top 2 sum by user by each day

    SELECT userid, sum(Score), datestamp
    FROM scores t1
    where 2 >=
    (SELECT count(*) 
     from scores t2
     where t1.score <= t2.score
     and t1.userid = t2.userid
     and day(t1.datestamp) = day(t2.datestamp)
     order by t2.score desc)
    group by userid, datestamp 
    ;
    

    Results for query 1:

    USERID  SUM(SCORE)  DATESTAMP
    1       70      December, 06 2012 00:00:00+0000
    1       30      December, 07 2012 00:00:00+0000
    2       22      December, 06 2012 00:00:00+0000
    2       25      December, 07 2012 00:00:00+0000
    3       30      December, 06 2012 00:00:00+0000
    3       30      December, 07 2012 00:00:00+0000
    

    Final Query: -- for all two days top 2 sum by user

    SELECT userid, sum(Score)
    FROM scores t1
    where 2 >=
    (SELECT count(*) 
     from scores t2
     where t1.score <= t2.score
     and t1.userid = t2.userid
     and day(t1.datestamp) = day(t2.datestamp)
     order by t2.score desc)
    group by userid
    ;
    

    Final Results:

    USERID  SUM(SCORE)
    1      100
    2      47
    3      60
    

    Here goes a snapshot of direct calculations of data I used.

    enter image description here

提交回复
热议问题