Single query to get the messages and count their answers - mysql

I have a mysql DB with two tables:
messages
message_answers
I'd like to fetch all messages and the number of answers for each of them, like:
first message (10 answers)
second message (5 answers)
Is it possible with a single sql query ?
I tried a query and a subquery for the count, but I don't know how to have the current id from the main query to make the "WHERE" restriction on the subquery (like: "message_answers.message_id = messages.id").
Thank you,
Sébastien

SELECT m.message, COUNT(ma.answer_id) AS AnswerCount
FROM messages m
LEFT JOIN message_answers ma
ON m.id = ma.message_id
GROUP BY m.message

select m.id, count(ma.id)
from messages m
join join message_answer ma on ma.id = m.message_id
group by 1

Related

How to get latest messages for each user in mysql? [duplicate]

This question already has answers here:
SQL select only rows with max value on a column [duplicate]
(27 answers)
Closed 2 years ago.
I have database to store customer and messages
I am trying to get list of all the customer and their latest messages like first screen in messenger.
SELECT *
FROM message AS m
LEFT JOIN customer AS c ON c.id=m.sender_id
ORDER BY m.sent_at DESC
but this returns all the message for all user. I've also tried doing this
SELECT *
FROM message AS m
LEFT JOIN customer AS c ON c.id=m.sender_id
GROUP BY c.id
but this doesn't run on all databases and cannot sort result set to get latest messages only.
One option uses row_number(), available in MySQL 8.0:
select * -- better enumerate the columns you want here
from customer as c
left join (
select m.*, row_number() over(partition by m.sender_id order by sent_at desc) rn
from messages m
) m on on c.id = m.sender_id and m.rn = 1
order by m.sent_at desc
This gives you the last message per customer. You can change the condition on rn if you want more messages (rn <= 3 would give you three messages per customer).
Note that I changed the order of the tables in the left join, so it allows customers without messages (rather than messages without customers, which probably does not make sense).
If you are running an earlier version, than an alternative is to filter with a subquery:
select * -- better enumerate the columns you want here
from customer as c
left join messages m
on m.sender_id = c.id
and sent_at = (select min(m1.sent_at) from messages m1 where m1.sender_id = m.sender_id)
For perforamnce with the correlated subquery, consider an index on (sender_id, sent_at) (ideally, there should be no duplicates in these columns).

MySQL: Order by max date of a joined table [duplicate]

This question already has answers here:
Ordering a MySQL result set by a MAX() value of another table
(2 answers)
Closed 4 years ago.
I have two tables - groups and messages.
Messages has the following fields group_id and date_created. So a lot of messages can be added to a single group. I want to select all groups from table - most relevant on top, i.e. order by latest message date. I've tried something like this
SELECT g.*, MAX(m.date_created) AS mdt FROM groups g
LEFT JOIN messages m ON g.id = m.group_id
ORDER BY mdt DESC;
But this query returns only one row and max message date from the whole table.
You are missing group by:
SELECT g.*, MAX(m.date_created) AS mdt
FROM groups g LEFT JOIN
messages m
ON g.id = m.group_id
GROUP BY g.id
ORDER BY mdt DESC;

Cannot run mysql count (*)

I am trying to run this query
SELECT a.id, count (*) as MovieCount
FROM actors a
JOIN roles r ON a.id = r.actor_id
GROUP BY a.id
but it underlines my * in red and says Error 1064. What could be wrong about the star in parentheses?
The problem (as explained in a comment and deleted answer) is the space after count.
However, you should be aware that you can significantly simplify the query by removing the join:
SELECT r.actor_id, count(*) as MovieCount
FROM roles r
GROUP BY r.actor_id

MySQL Group By single result order by time

I am trying to fetch users from messages table which has send message to me but need only one result per sender which is max of creation column which is time of message creation
SELECT messages.from, account_images.profile, bio.user_full_name
FROM messages
INNER JOIN account_images ON account_images.uuid=messages.from
INNER JOIN bio ON bio.uuid=messages.from
WHERE messages.to='me'
GROUP BY messages.from
ORDER BY messages.creation DESC
A user whose message is created recently must be on top but it not coming on top using this code. I referred php mysql Group By to get latest record, not first record but not getting anything
Any help?
You could have written the current query as...
SELECT DISTINCT messages.from, account_images.profile, bio.user_full_name
FROM messages
INNER JOIN account_images ON account_images.uuid=messages.from
INNER JOIN bio ON bio.uuid=messages.from
WHERE messages.to='me'
Which would have been marginally more efficient - but as you will have noticed with your current query, it doesn't get sorted by the most recent message.
This is sorted as you request:
SELECT messages.from, account_images.profile, bio.user_full_name
FROM messages
INNER JOIN account_images ON account_images.uuid=messages.from
INNER JOIN bio ON bio.uuid=messages.from
WHERE messages.to='me'
GROUP BY messages.from
ORDER BY MAX(messages.creation) DESC;
It is possible to get the result you desire using DISTINCT instead of aggregation, but it's neither efficient nor elegant.
I found this mysql doc very helpful in cases like this: http://dev.mysql.com/doc/refman/5.0/en/example-maximum-row.html
SELECT *
FROM messages m
LEFT JOIN messages m2 ON m.creation > m2.creation
WHERE m2.creation IS NULL
AND m1.to='me'

sql nested inner join only returning 1 result

I'm building a Chatapplication that's a bit like the facebookchat. I have users,conversations and messages. All 3 have their own tables. For now I try to get all converstations containing a certain user and the latest message of the conversation.
I tried this query, but in a fact I only get 1 row back, but there are more rows matching
SELECT conversations.id as converid,
messages.from as messageauthor,
messages.message as message
FROM conversations INNER JOIN (SELECT * FROM messages
ORDER BY date DESC LIMIT 1) as messages
ON messages.conversationid=conversations.id
WHERE user1=3
OR user2=3
When I do i.e.
SELECT conversations.id as converid,
messages.from as messageauthor
FROM conversations INNER JOIN messages
ON messages.conversationid=conversations.id
WHERE user1=3
OR user2=3
I get all results, for sure, and when I check the converid's I get 3 unique Id's, so at least there are 3 converstations going on with userid 3. So the top query should also return 3. Now I don't understand why it only returns 1 row. Does the limit 1 from the nested query affect the whole query?
Looking forward for some pointers...
No. The limit 1 affects the subquery, so it is only returning one row. So, there is only one match.
What is the issue with this query (your second query, but formatted differently):
SELECT c.id as converid, m.from as messageauthor
FROM conversations c INNER JOIN
messages m
ON m.conversationid=c.id
WHERE user1=3 OR user2=3;
I see, you want the latest message. Try calculating it and joining back in:
SELECT c.id as converid, m.from as messageauthor
FROM conversations c INNER JOIN
messages m
ON m.conversationid=c.id join
(select m.conversationid, max(date) as maxdate
from messages m
group by m.conversationid
) mmax
on mmax.conversationid = m.conversationid and m.date = mmax.maxdate
WHERE user1=3 OR user2=3;