This question has been asked 1000 times, but I can't get it to work by modifying other peoples examples.
I have a messages table:
id
message
reciever_id
reciever_seen
sender_id
I want to create a mysql query that will show only the latest message sent for each conversation.
There can only be 1 conversation from user to user, and conversations cannot be deleted (for now)
The best answer will go to the responder who explains in detail how the query functions work together to give the results.
Related
I've a SQL table which contains all the users and groups conversation in it. I'm able to retrieve group conversation from it easily but don't know how to retrieve last messages of each user from it.
Explanation of columns:
• message_id: Self explanatory
• group_id: Since the conversation also contains group messages, I'll use group_id to filter those messages instead of creating a new messaging table for it.
• user: Sender/Receiver (It can be both sender or receiver by defining the value on last column 'isReceived').
• message: Self explanatory
• creation: Self explanatory
• isSeen: If the message has been seen by the user (receiver).
• isError: If there was an error while sending the message.
• isReceived: To check whether the message was received or send by the default user.
Now what I really want is to retrieve last messages of all conversations no matter if its sent or received. Example, 'Sondre' (Another User) sent me a message "Hi" and now I sent him a reply/message "Hello" and when I retrieve data from messages table I want my reply to be shown instead of his. I've also uploaded photos of current data and the data using query I want:
Data of messages table:
Data I want using query:
You need to do it in two parts first get the latest messages, grouped by user
Then fetch your messages against these
Simplest answer is (it would work fine if you really have message_id a unique/primary key)
select * from messages where message_id in
(select max(message_id) from messages group by user)
It will give you the latest message from each user, Yo can also group by other things instead of user
The better version you need (for better performance with scalability) is
select messages.* from messages
join
(select max(creation) maxtime,user from messages group by user) latest
on messages.creation=latest.maxtime and messages.user=latest.user;
Abvove will work even if you do not have a unique/primary key column like message_id, but if you really have it then i would recommend to use message_id instead of creation
you can see implemented SQL Fiddle Demo
I have a Postings table (with data of people posting a service they offer) and a table of people that have corresponded (written mails) to these Posting authors thus starting a Transaction (inserted into a second table: Transactions).
Each Posting can have many transactions. Each time a user Logs-in he/she (Transaction_Taker) can send mail to the author (Posting_Author) of his choice.
Each first mail generates a new Transaction and its Transaction_Id (int) is appended to Postings table in the varchar, hyphen-separated Posting_Transaction_List field.
The contents of each subsequent mail that same (logged-in) user (aka Transaction_Taker) sends, does not create/insert a new transaction (nothing inserted to field Posting_Transaction_List) but rather is appended (update) to the Transaction that was started initially by that user for that Posting.
For easy navigation and search, once a user has logged in, I show an ajax generated list of all these postings such that each Posting only shows once though it can have many transactions. In other words I need to show a list of all available Postings including the ones this (logged-in) user has started a Transaction for, but these postings (the ones in which this user has an ongoing transaction) should show, but we should not show that same Posting with OTHER user's transactions. That is, only the logged-in user should see his/her transactions.
Assuming I have table Postings with fields: Posting_Id (int), Posting_Author (varchar), Posting_Content (text), Posting_Transaction_List (varchar)
…and table Transactions with fields: Transaction_Id (int), Transaction_Posting_Id (int), Transaction_Taker_Id (int)
I am (almost) achieving my goal with the following SQL:
$AlmostGoodSQL = "SELECT *, Posting_Id FROM Postings LEFT JOIN Transactions ON
Postings.Posting_Id = Transactions.Transaction_Posting_Id WHERE Posting_Content
LIKE '%"+$SomeSearchString+"%' GROUP BY Posting_Id";
The problem is this shows a distinct instance of each Posting, but not necessarily the ones that have to do with the logged-in user (in the case where there are many transactions -including hers- for a Posting). To do this, I would need to select ALL Postings without transactions attached PLUS those that have Transactions just for this user BEFORE doing the group by. This is what I cannot achieve. I believe that due to the way 'group by' works you could maybe select maximum or minimum values, but not an exact match, say for all the Postings that have Transactions with user (Transaction_Taker) '123456'. I think "group by" shows whichever instance it finds first. How to make it match my criteria?
It does not look like a subquery would do, but rather like something conditional, like: "Search for all Postings and if the Posting has a Transaction listed in the Posting_Transaction_List that points to a Transaction where the Transaction_Taker_Id is the one of the logged-in user ($UserId), then show it distinctly (just that one, once)"… and I don't know how to do all that in SQL: Can anybody please help?
I'm trying to implement a messaging system in PHP and MySQL but I'm having some trouble deciding on how I should do the tables and queries.
What would be the best approach for a system that allows for multiple participants? I'm thinking I'd probably need 3 tables (aside from an users table).
Something like
Conversation
------------
id
Messages
--------
id
conversation_id
from_id
subject
message
from_timestamp
Participants
------------
conversation_id
user_id
last_read_timestamp
The way it is setup I'd have to check for read messages by the timestamp instead of ticking off each message. I'd also be able to add participants at any time.
What do you guys think?
Thanks in advance.
I don't see much to complain about :) I'd probably cache the last modification date on the conversations table so that a list of "unread" conversations can be displayed quickly. This date would be updated each time a message is posted on the conversation.
I would have put the subject field on the conversation table. Putting it on every single message looks redundant.
Also, I'd save the creation time and the author user id of the conversation in its table.
The communication between Facebook users seem to be stored in one long "conversation." So, emails sent and private chat messages exchanged all seem to be part of one long ongoing conversation.
I think this implementation works well for users (at least it does for me). I assume the table design for this part could be implemented this way:
TABLE: message
- message_id
- timestamp
- from_user_id
- to_user_id
- message
What if I wanted to support group chat? Would I do something like this:
TABLE: message
- message_id
- timestamp
- from_user_id
- message
TABLE: message_recipient
- message_recipient_id
- message_id
- to_user_id
I think it'll work. However, I'm wondering if it would make sense to the user if I displayed every single things that user has ever messaged anyone in one long conversation. It probably wont. Imagine a conversation with Person A mixed with group conversation with Person A, B, C, D mixed with conversation with Person E and so on ....
Any suggestion on what would be a usable concept to implement?
I believe a message should be an entity, regardless of platform or sender/receiver, with id,message,timestamp fields, and a message relation table - like you suggested - with id,message_id,from_id,to_id.
Then, if you are showing a single user to user conversation, you can show every message between them.
For group chats, you should have a table with id,title,timestamp that holds the group chat main record, and another table that holds the users that are part of that group chat, with id,group_chat_id,user_id fields.
Just my opinion and how I would implement it.
Edit: Maybe it would make sense to have from_id on the message entity itself, as a message has to have a singular sender id.
You could also group messages by topics.
You add a topic table. You add a recipients table, tied to a topic. Messages will also be tied to a topic.
You can programmatically limit the topics between two users by looking which topic has those two users in its recipients.
You could also separate your messages by giving them a type attribute. For example, type 0 will be an inbox message, type 1 will be a chat message and so on.
If I wanted to have an arbitrary number of recipients in one topic, I would avoid the from_id/to_id combo.
I have an app that manages conversations between users on a website. It does one to one conversations as well as having multiple people in a single conversation.
Here is the layout for the mysql tables
conversations
conversations_meta
The conversations_meta table links users to the conversations by logging user_id and conversation_id. It also holds meta info about the conversation specific to each user in the conversation.
What I am having trouble with is detecting if a conversation with the same people already exist.
For example if a conversation between Eric Jason and bob exists but maybe it's old and the user forgot about it and then tries to create an addition conversation with the same users I would like to notify them of the conversation.
So the query should look in conversations_meta table and compare user_id and conversation_id to see if the same conversation exists already. Also I wouldn't want it to return conversations that include all the same users and additional users as well.
The main reason I posted this question on here is to get the fastest query possible to accomplish this task since there will be thousands of conversations.
What about this:
SELECT conversations_meta.conversations_id FROM conversations_meta
where (conversations_meta.user_id=1) or (conversations_meta.user_id=2)
group by conversations_id HAVING count(*) = 2
NOTE: this is a case for only 2 people in the conversation. Easily expanded to the case of 3 or or more.