简体   繁体   中英

get last record of each user for each category

I want to get the last record of each user for each category.

eg I have a table

tests (test_id,cat_id,user_id,score,time)

I need each user last record for each category. I can use group by either category_id or by user_id but I am not getting how to get my desired result?

eg I have following records

test_id | cat_id | user_id | score | time
      1 |      1 |      11 |    20 | 2016-11-12 01:11:11
      2 |      2 |      11 |    24 | 2016-11-12 01:11:11
      3 |      1 |      12 |    25 | 2016-11-12 01:11:11
      4 |      3 |      12 |    21 | 2016-11-12 01:11:11
      5 |      1 |      13 |    22 | 2016-11-12 01:11:11
      6 |      2 |      12 |    23 | 2016-11-12 01:11:11
      7 |      2 |      12 |    27 | 2016-11-12 01:11:11
      8 |      1 |      11 |    21 | 2016-11-12 01:11:11

Now I need following result

test_id | cat_id | user_id | score | time
      2 |      2 |      11 |    24 | 2016-11-12 01:11:11
      3 |      1 |      12 |    25 | 2016-11-12 01:11:11
      4 |      3 |      12 |    21 | 2016-11-12 01:11:11
      5 |      1 |      13 |    22 | 2016-11-12 01:11:11
      7 |      2 |      12 |    27 | 2016-11-12 01:11:11
      8 |      1 |      11 |    21 | 2016-11-12 01:11:11

In above o/p each user's only last result is coming of each category.

The query you need is:

SELECT l.test_id, l.cat_id, l.user_id, l.score, l.time
FROM tests l                     # "l" from "last"
LEFT JOIN tests n                # "n" from "next"
    ON l.user_id = n.user_id     # match user
    AND l.cat_id = n.cat_id      # and category
    AND l.time <= n.time         # "next" is not before "last" (check the time)
    AND l.test_id < n.test_id    # "next" is after "last" when the times are equal
WHERE n.test_id IS NULL          # there is no "next" matching the JOIN conditions

How it works

The query joins test aliased as l (from "last") against itself aliased as n (from "next" after "last"). The LEFT JOIN ensures that all the rows from l are included in the join. Each row from l is paired with all the rows from n that contain the same user_id and cat_id ("each user, each category") and have greater values in columns time and test_id . Because it's technically possible to have two rows with the same values in columns user_id , cat_id and time , on equal times match the row from l with a row from n that was input in the database later (it has a bigger auto-incremented test_id ).

When a row that fulfills all the ON conditions is not found in n , the row from l is paired with a row full of NULL s.

The WHERE condition keeps only the rows having NULL in n.test_id . They are the rows from l that don't have a match in n (because there is no row in n having a bigger value in the time column or a bigger test_id when the times are equal). These are the last records for each (user, category) pair.

试试这个SELECT MAX(user_id) FROM tests GROUP BY cat_id

Here we need a last user for all categories. SO we have to do group by category and find the user which have highest time for it.

SELECT t1.* 
FROM tests t1
INNER JOIN
(
    SELECT max(time) MaxTime,user_id,cat_id
    FROM tests
    GROUP BY user_id,cat_id
) t2
  ON t1.user_id = t2.user_id
  AND t1.cat_id = t2.cat_id
  AND t1.time = t2.MaxTime
order by t1.time desc

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM