简体   繁体   中英

Sort results of a query from associative table order

I am trying to sort the results of a query by the order present in the associative table. I have three tables:

  • users
  • restaurants
  • restaurant_user_view

restaurant_user_view contains a row for each time a user has viewed a restaurant. The tables, in a simplified version, have this structure:

restaurants:

| id | name |
|----|------|
| 1  | Restaurant A|
| 2  | Restaurant B|
| 3  | Restaurant C|
| 4  | Restaurant D|

users:

| id | name |
|----|------|
| 1  | User A|

restaurant_user_view:

| id | user_id | restaurant_id | Timestamp |
|----|---------|---------------|-----------|
| 1  |    1    |        1      |     xxxxx |
| 2  |    1    |        3      |     xxxxx |
| 3  |    1    |        4      |     xxxxx |
| 4  |    1    |        3      |     xxxxx |
| 5  |    1    |        2      |     xxxxx |
| 6  |    1    |        3      |     xxxxx |
| 7  |    1    |        1      |     xxxxx |
| 8  |    1    |        1      |     xxxxx |

At the semantic level, I would like to have the last 3 restaurants visited, so the expected output is: Restaurant A, C, B with the restaurant_id in restaurant_user_view table: 1, 3, 2. The restaurant_user_view id is: 8, 6, 5.

I wrote this query:

SELECT restaurants.*, restaurant_user_view.timestamp
FROM restaurants 
LEFT JOIN restaurant_user_view ON restaurants.id = restaurant_user_view.restaurant_id
WHERE restaurant_user_view.user_id = 1
GROUP BY restaurants.id
ORDER BY restaurant_user_view.timestamp DESC

But I get this output: restaurant_user_view.restaurant_id : 2, 4, 3, because of those are the last visited restaurants after the group by statement.

I haven't found any solution online, from what I have understood the problem lies in how the group by is handled by mysql. Any solutions?

You can do the aggregation in a derived table to get the maximum timestamp (ie the youngest visit) for each restaurant. Join in the outer query and use ORDER BY and LIMIT to get only the youngest three visits.

SELECT r.*,
       x.timestamp
       FROM (SELECT ru.restaurant_id,
                    max(ru.timestamp) timestamp
                    FROM restaurant_user_view ru
                    WHERE ru.user_id = 1
                    GROUP BY ru.restaurant_id) x
            INNER JOIN restaurants r
                       ON r.id = x.restaurant_id
       ORDER BY x.timestamp DESC
       LIMIT 3;

Note: Besides not solving your problem, your query is malformed. There are columns in the list of selected columns that neither are in the GROUP BY clause nor an argument to an aggregation function. Sadly instances of old MySQL versions or badly configured ones accept such erroneous queries. But the result can suddenly be funny.

Also note: A timestamp should not be an integer . There are datetime and timestamp data types in MySQL. They, unlike integer s allow date/time arithmetic on them.

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