Reputation: 23
I have two tables. My task is to choose the last person comment.
db_user (db_user_id, name, balance)
db_comment (db_comment_id, db_user_id, text)
My query:
SELECT db_user.name,db_comment.text
FROM db_user INNER JOIN db_comment ON db_user.db_user_id = db_comment.db_user_id
ORDER BY db_comment.db_user_id DESC
Tried to use LIMIT
but failed.
A table with values has already been created here: http://sqlfiddle.com/#!9/badaf/14
My data sampling should receive the last comment (db comment.text
) from each person (db_user.name
).
Сondition, you cannot add new fields.
Upvotes: 2
Views: 249
Reputation: 11602
Other approach without the need to use MAX(db_comment_id)
or GROUP BY db_user_id
and complety works by filtering
Query
SELECT
db_user.name
, db_comment1.text
FROM
db_comment db_comment1
LEFT JOIN
db_comment db_comment2
ON
db_comment1.db_user_id = db_comment2.db_user_id
AND
db_comment1.db_comment_id < db_comment2.db_comment_id
INNER JOIN
db_user
ON
db_comment1.db_user_id = db_user.db_user_id
WHERE
db_comment2.db_user_id IS NULL
Note: Using db_comment1.db_comment_id > db_comment2.db_comment_id
instead would do MIN(db_comment_id)
yes the operator direction can feel pretty bit counterintuitive and it is very easy to get wrong and write the wrong one (that's why i needed to edit mine answer...) , see demo..
Result
| name | text |
|-------|----------------|
| Ivan | Message3 ivan |
| Petr | Message3 Petr |
| Artur | Message2 Artur |
| John | Message2 John |
Performance note: it needs to have the INDEX(db_user_id, db_comment_id)
on the db_comment
table otherwise it will not be very fast. If you have that index, MySQL should be able to handle (very) large tables when running this query..
see demo
Upvotes: 0
Reputation: 67
Try it -
SELECT db_user.name,db_comment.text
FROM db_user
INNER JOIN db_comment
ON db_user.db_user_id = db_comment.db_user_id
ORDER BY db_user.db_user_id DESC, db_comment.db_comment_id desc
limit 1
OR
SELECT db_user.name,db_comment.text
FROM db_user
JOIN (
select db_comment_id as maxId, db_user_id, text
from db_comment
order by db_comment_id desc
limit 1
) as db_comment ON db_comment.db_user_id = db_user.db_user_id
ORDER BY db_user.db_user_id DESC`
if the limit is not working then you can use the MAX function and make join self table
Upvotes: 0
Reputation: 43574
You can use the following solution using a additional JOIN
:
SELECT dbu.name, dbc.text
FROM db_user dbu INNER JOIN (
SELECT MAX(db_comment_id) AS db_comment_id, db_user_id
FROM db_comment
GROUP BY db_user_id
) dbc_max ON dbu.db_user_id = dbc_max.db_user_id
INNER JOIN db_comment dbc ON dbu.db_user_id = dbc_max.db_user_id
AND dbc.db_comment_id = dbc_max.db_comment_id
ORDER BY dbu.db_user_id DESC
... or using a sub-select directly on the SELECT
:
SELECT dbu.name, (
SELECT `text`
FROM db_comment dbc
WHERE dbu.db_user_id = dbc.db_user_id
ORDER BY dbc.db_comment_id DESC
LIMIT 1
) AS `text`
FROM db_user dbu
ORDER BY dbu.db_user_id DESC
Upvotes: 1
Reputation: 94884
The last comment is the one with the highest ID. So, make sure there doesn't exist a higher one for the user:
SELECT
u.name,
c.text
FROM db_user u
JOIN db_comment c ON c.db_user_id = u.db_user_id
AND NOT EXISTS
(
SELECT *
FROM db_comment c2
WHERE c2.db_user_id = c.db_user_id
AND c2.db_comment_id > c.db_comment_id
);
Or work with a list of highest comment IDs per user:
SELECT
u.name,
c.text
FROM db_user u
JOIN db_comment c ON c.db_user_id = u.db_user_id
AND (c.db_user_id, c.db_comment_id) IN
(
SELECT db_user_id, MAX(db_comment_id)
FROM db_comment
GROUP BY db_user_id
);
As of MySQL 8 you can also use window function. E.g.:
SELECT
u.name,
c.text
FROM db_user u
JOIN
(
SELECT
db_user_id,
text,
ROW_NUMBER() OVER (PARTITION BY db_user_id ORDER BY db_comment_id DESC) AS rn
FROM db_comment
) c ON c.db_user_id = u.db_user_id AND c.rn = 1;
Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=2c2c67cdba80a992b593e4c74201fa61
Upvotes: 0
Reputation: 222432
I would use a correlated subquery for filtering. In many cases, this is approach that has the best performance, especially with an index on db_comment(db_user_id, db_comment_id)
:
select u.name, c.text
from
db_user u
inner join db_comment c on c.db_user_id = u.db_user_id
where c.db_comment_id = (
select max(c1.db_comment_id)
from db_comment c1
where c1.db_user_id = c.db_user_id
)
This assumes that the last comment is the one that has the highest db_comment_id
.
name text
Ivan Message3 ivan
Petr Message3 Petr
Artur Message2 Artur
John Message2 John
Upvotes: 0