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.
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
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. Eg:
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
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
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
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
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.