MYSQL Many-to-many select (chats, latest message, username) in one statement - mysql

I'm trying to select a list of the user's chats in one statement, together with each chats latest message and the massage's sender's name.
The abstract problem is:
Ever chat can have multiple participating users.
A message is sent to a "chat", not a specific user.
These are the tables I came up with
TABLE users (id, username)
TABLE chats (id)
TABLE messages (id, message, chat_id, user_id)
And lastly a many-to-many relation table between chats and participants
TABLE chats_users (chat_id,user_id)
I want to list all the chats a certain user participates in, together with the latest message and it's sender's username.
How would I go about that in one statement?
Im running Mysql 5.0.9 and php 7.

This query:
select max(m.id) id
from chats_users cu
inner join users u on cu.user_id = u.id
inner join messages m on m.chat_id = cu.chat_id
where cu.chat_id in (select chat_id from chats_users where user_id = ?)
group by cu.chat_id
returns the last messages of all the chats that a certain user participates.
Use it in this query:
select m.chat_id, m.message, u.username
from messages m inner join users u
on u.id = m.user_id
where m.id in (
select max(m.id) id
from chats_users cu
inner join users u on cu.user_id = u.id
inner join messages m on m.chat_id = cu.chat_id
where cu.chat_id in (select chat_id from chats_users where user_id = ?)
group by cu.chat_id
)
to get the details of these messages.

Related

Sql query correction one to many tables

I have two tables one is users and second is user_education.One users can have more than one education listing so i want to get the latest user education listing
users
===============
1-id
2-email
member_experience
==============
1-id
2-user_id
3-designation
user id 1 has 4 enteries in user_education so i want to get the last record enter designation of the user
original full query is like this
SELECT u.id,u.name,u.gender,u.email,file_managed.file_name,file_managed.file_path
from users as u
INNER JOIN member_experience on (SELECT uid FROM member_experience where member_experience.uid=u.id ORDER BY id DESC LIMIT 1)=u.id
LEFT JOIN file_managed on file_managed.id= u.fid
where u.user_type ='individual' AND u.gender='male'
"INNER JOIN member_experience on (SELECT uid FROM member_experience where member_experience.uid=u.id ORDER BY id DESC LIMIT 1)=u.id "
this portion has problem as users has many record in member_experience table but i want to get only one which is latest.
thanks
Devolve the acquisition of the last record to the where statement.
drop table if exists member_experience;
create table member_experience(id int auto_increment primary key, userid int);
insert into member_experience (userid) values
(1),(2),(1);
select * from member_experience
SELECT u.id,m.id
from users as u
join member_experience m on m.userid = u.id
where m.id = (SELECT max(m.id) FROM member_experience m where m.userid = u.id)
order by u.id
Or if you want to include those with no experience
SELECT u.id,m.id
from users as u
left join member_experience m on m.userid = u.id
where (m.id = (SELECT max(m.id) FROM member_experience m where m.userid = u.id)
or m.id is null)
and u.id < 4
order by u.id

Query: How to obtain the most recent message per one user conversations?

I have a conversations table that is very simple but important (created_by is the code of the user who sent the message). Then, I have a conversations_messages table (sent_by is the code of the user who sent the message, message is my message text and created_at is the timestamp). Finally I have a conversations_users table that has the user_id (code of the user who received the message) and created_by (code of the user who sent the message).
I am trying to implement the functionality of inbox, I want to show the last message per conversation. user_id in conversations_users is the user who received the message and the user who is consulting his inbox.
I tried this query but I don't know how to deal with the created_at timestamp (in table conversations_messages) in order to get the most recent message per conversation.
select CM.id, CM.message, CM.created_at, C.id as 'conversation_id' from conversations_users CU
join conversations C on CU.conversation_id = C.id join conversations_messages CM on C.id = CM.conversation_id where CU.user_id = 1 and CM.created_at = '2015-03-10 14:18:02'
I have to replace '2015-03-10 14:18:02' for some most recent created_at timestamp thats my problem.
My tables are:
conversations_users: id, conversation_id, user_id, created_by
conversations: id, created_by
conversations_messages: id, conversation_id, sent_by, message, created_at
Thanks!
SELECT cm.*
FROM conversations_messages cm
JOIN conversations c ON cm.conversation_id = c.id
JOIN conversations_users cu ON cu.conversation_id = c.id
WHERE cu.user_id = 1
AND NOT EXISTS ( SELECT 'a'
FROM conversations_messages cm2
WHERE cm2.conversation_id = cm.conversation_id
AND cm2.created_at > cm.created_at
)
GROUP BY c.id
Here's one approach joining the table back to itself using the max aggregate, grouping by each conversation:
select CM.id, CM.message, CM.created_at, C.id as 'conversation_id'
from conversations_users CU
join conversations C on CU.conversation_id = C.id
join conversations_messages CM on C.id = CM.conversation_id
join (
select max(created_at) maxcreated_at, conversation_id
from conversations
group by conversation_id
) T on T.maxcreated_at = CM.created_at
and T.conversation_id = CM.conversation_id
where CU.user_id = 1

Find records which are not exists in other table

I've this table structure:
-request
request_id
user_id
-user
user_id
company_id
-company
company_id
I want to select all those records from requests table where user_id=? and no such records where the company id of to users is same.
This is usually achieved using LEFT JOIN:
SELECT r.*
FROM request r
JOIN user u ON r.user_id = u.user_id
LEFT JOIN u1 ON u1.user_id != u.user_id AND u1.company_id = u.company_id
LEFT JOIN request r1 ON r1.user_id = u1.user_id
WHERE r1.user_id IS NULL
By "where" we say that we don't want "users with same company, who has at least 1 request"

Reference outside inner join query

I have the following query for a basic messaging system. It shows the messages that you've sent. However, it is showing the first_name and second_name for the account referenced by sender_id. Instead I want it to output the name columns referenced by receiver_id
ie) SELECT first_name, second_name WHERE accounts.account_id = messages.receiver_id
Do I need to write a seperate query for this or can I make this one output it in a single query? I've been thinking quite hard about this problem!
SELECT first_name, second_name, message_id, title, body, seen, urgent, type, messages.timestamp
FROM messages
INNER JOIN accounts
ON messages.sender_id=accounts.account_id
WHERE sender_id = ?
You can do this with two joins:
SELECT s.first_name as sender_first, s.second_name as sender_last,
r.first_name as rec_first, r.second_name as rec_last,
m.message_id, m.title, m.body, m.seen, m.urgent, m.type, m.timestamp
FROM messages m inner join
accounts s
ON m.sender_id = s.account_id inner join
accounts r
on m.receiver_id = r.account_id
WHERE m.sender_id = ?

Complex MySQL search query

I have below query running on my users and chats table to join and I'm trying to group by on my chats table for user_id OR receiver_id not just user_id like you can see below in SQL query inside INNER JOIN.
SELECT c.*, users.username, users.firstname, users.lastname
FROM chats c
INNER JOIN( SELECT MAX(created) AS Date, user_id, receiver_id, chat, type, id
FROM chats
WHERE receiver_id = 286 OR user_id = 286
GROUP BY user_id ) cc ON cc.Date = c.created AND cc.user_id = c.user_id
LEFT JOIN users ON users.id = c.user_id
WHERE c.receiver_id = 286 OR c.user_id = 286
I tried GROUP BY user_id OR receiver_id but I can't seem to get information for id 286 for either receiver_id or user_id.
Is there a way we can achieve it and group by so that we can look into both columns and come up with results from both?
Do I need to do two queries and join them together instead?
If you are looking for most recent chat record, why don't you just sort the results by created and get the first row like this:
SELECT c.*, users.username, users.firstname, users.lastname
FROM chats c, users u
WHERE (c.receiver_id = 286 OR c.user_id = 286) AND
u.id = c.user_id
ORDER BY created DESC
LIMIT 1