I am creating php messaging system based with conversations. And I got a problem.
I have a table with columns: id, to, from, msgtext, timesent, viewed, deleted.
I want to select just one conversation between to and from. Take a notice that if user to can write a message to user from.
How to select seperate conversations?
I am trying with this SQL:
SELECT to, from FROM pms WHERE to='$userid' OR from = $userid group by to ORDER by id desc LIMIT 50
But this does not work another way. Because if user1 wrote message to user2, and user2 replied to user1, and again if user1 replies and user2 replies, i see as 2 conversations, but it should be as one conversation.
It should be like this:
User sends a message to some other user. It should show in conversations list That other user's name.
If user gets a message from another user, he should see his name in the conversation list.
Try this code
SELECT `id`, `to`, `from`, `msgtext`, `timesent`, `viewed`, `deleted` FROM table_name
WHERE `to` = 'username_to' AND `from` = 'username_from'
LIMIT 1
OFFSET 0
If you understand the concept behind you will realize that you need to play only with OFFSET number to get the next record.
P.S. A shortcut to the LIMIT & OFFSET lines above is:
LIMIT 0, 1
Also, when you ask something on Stack Overflow you are supposed to show what you have tried, and ask why is not working, instead of simply asking for code.
Related
I have a php chat system that I am working on. I have an issue where the query statement to grab the message is selecting them, grouping them by the two users that it was sent to and from, and then outputs the html.
Right now it only is outputting from the beginning of the first chat id to the last id when a user goes to select a chat.
I would like to sort it by the most recent chat on top because as of the moment, it is going from top to bottom from the first user that has sent a message to the last user that has sent a message. For example, if "user 1" hasn't sent a message for a while, that user will always be the first one to be outputted by the query statement, even though "user 6" has sent 8 new chats, "user 6" will still be the last one on the list to select from, this should be the opposite and the newest chat group should appear on top. I just don't know how to do that with my SQL query.
My current query statement is:
$queryall = "SELECT DISTINCT mfrom FROM chat WHERE mto='user2'";
I know it's coded wrong for what I want, and i've tried a lot of different things, can't seem to get it to do what I want. I've tried order by datesent and grouping them, but couldn't get anything to work. I believe DISTINCT is not allowing me to do it based of syntax things I am not familiar with.
mysql database row
User2 chat view
You just need a simple ORDER BY:
$queryall = "SELECT DISTINCT mfrom FROM chat WHERE mto='user2' ORDER BY datesent DESC";
This orders your result set by column datesent in DESC (descending) order (newest to oldest when used on date/datetime column).
When your users have multiple messages, you may want to use GROUP BY instead of DISTINCT
$queryall = "SELECT mfrom FROM chat WHERE mto='user2' GROUP BY mfrom ORDER BY MAX(datesent) DESC";
I am struggling with this for several hours already. I am coding a messaging system and my table has the following columns:
ID(UUID) | from_user_id(uuid) | to_user_id(uuid) | subject | body | created_at
In inbox page I need to get the results grouped by subject+from_user_id. That is required because if the subject is the same then it is a separate dialogue and from_user_id should be concatenated with subject to make sure that if the other user will send a message with the same subject it will not be merged with other dialogue.
Second thing is that for each group I need to get the first message to show as dialogue cover message. It would be pretty easy to solve problem if I has normal ID's used but instead I am using UUID,s so I cannot use min or max for them. So I need to use created_at field to determine which row is the last.
I have tried many different approaches but I cannot get the result I need. Maybe anybody had similar problem before and has a solution?
select msg.id, msg.body, msg.created_at, concat(msg.from_user_id, msg.subject) as concat
from messages as msg
where msg.to_user_id = '8d99eb39-24f8-4dd6-b984-9505cd3eb6b6'
order by msg.created_at desc limit 10 offset 0
Basically you need the subquery to identify the last message in each thread,
and then select against that subquery to get the details from each of those last messsages
select * from messages
where to_user_id = 'jim'
and concat(from_user_id, subject, created_at) in (
select max(concat(from_user_id, subject, created_at))
from messages
where to_user_id = 'jim'
group by concat(from_user_id, subject))
I am displaying the message status that differs from each user. Let's say user1 sends a message to user2, user1's message status then sets to read, while user2's message is set to unread by default. It will be updated after user2 clicks the message.
So in these scenario, the message of user1 (from the inbox) will have a gray-colored font which indicates that the message is set to read (since user1 is the one who is sending). On the other side, user2 have a bold font that indicates that the message is unread.
Here is the first structure of the table:
message(messageid, fromid, toid, message, timestamp, status)
The problem here is that if I update the message status to read, it affects the other side (user2). So I add another column that will set the status differently from user1 and user2:
message(messageid, fromid, toid, message, timestamp, from_status, to_status)
Here, from_status is for the fromid and to_status is for toid. But I'm having a problem on how to use these values to display the status.
The PHP code of that I use during my first attempt is these:
<?php
$id = $_SESSION['id'];
$query = mysql_query("SELECT m.* FROM message m
LEFT JOIN message m2 ON (
(m.fromid=m2.fromid AND m.toid=m2.toid) OR
(m.fromid=m2.toid AND m.toid=m2.fromid)
) AND m.timestamp<m2.timestamp
WHERE (m.fromid='$id' OR m.toid='$id') AND m2.toid IS NULL ORDER BY timestamp DESC");
while ($message = mysql_fetch_array($query)) {
if ($message['status'] === 'unread') {
// bold font style will be applied
}
else {
// gray-colored font will be applied
}
}
?>
(The query fetches each conversation from every user with the latest conversation.)
These code works fine for the main user, which is user1, but affects the other side, which views that the message received from user2 is set to read instead or unread.
So, I'm having some trouble on what to do on the modified table, having 2 separate status each for each user. How can I get these done?
#andrewsi comment is quite nice, when you'll have for example many receivers. In your case it's only one additional field, so in my opinion it's not an overflow to use just one table.
Regarding your case you can do this in one simple sql:
SELECT m.*,
CASE
WHEN m.fromid = $id THEN m.from_status
WHEN m.toid = $id THEN m.to_status
END as read_status
FROM message m
WHERE
m.fromid = $id OR m.toid = $id
ORDER BY timestamp DESC;
And in your view you are only checking the read_status field
(Posted on behalf of the OP.)
I've managed to solve the problem, thanks to #Rafal Mnich. So I grab a part of his query and do a bit of modification, and it works.
Here's the query:
SELECT m.msgid, m.fromid, m.toid, m.content,
CASE
WHEN m.fromid = '$id' THEN m.frommsgstatus
WHEN m.toid = '$id' THEN m.tomsgstatus
END AS msgstatus
FROM msg m
LEFT JOIN msg m2
ON ((m.fromid=m2.fromid AND m.toid=m2.toid) OR (m.fromid=m2.toid AND m.toid=m2.fromid)) AND m.timestamp<m2.timestamp
WHERE (m.fromid='$id' OR m.toid='$id') AND m2.toid IS NULL
ORDER BY m.timestamp DESC
These displays the messages grouped by the sender fromid, which also displays the latest conversation you have from each of the senders. And it displays the correct message status in both sides of the users.
I got a message system with a table like this
ID AID FID MESSAGE
1 1 2 Hi
2 2 1 Hi, how are you?
3 3 1 Hello One, what's up?
4 1 2 I'm fine, how about you?
ID is the unique Message-ID, AID the ID of the transmitter and FID the ID of the receiver of the message. Message is the message itself.
I want to select all unique combinations with the highest ID, but only once, so the output looks like this:
ID AID FID MESSAGE
3 3 1 Hello One, what's up?
4 1 2 I'm fine, how about you?
The problem is that I can't select properly as AID=2 and FID=1 is as unique as FID=1 and AID=2, but it's in fact the same conversation.
Any suggestions would be very appreciated!
EDIT: The ID of the user currently logged in is $_SESSION["said"]
EDIT 2: The message system should look something like this, displaying the last message sent in a conversation (just like on facebook).
http://i.stack.imgur.com/Jmvfr.jpg
here is query:
select * from table
where ID in (
select max(id) as maxid
from table
group by LEAST(aid, fid), GREATEST(aid, fid)
)
if you want to select last message only from/to $_SESSION["said"], you can use:
$query = "select * from table
where ID in (
select max(id) as maxid
from table
where aid = ".$_SESSION["said"]." or fid = ".$_SESSION["said"]."
group by LEAST(aid, fid), GREATEST(aid, fid)
)";
it will give you list of all latest messages sent to/from this user
Might have to modify it depending on your RDBMS (MySQL vs. Microsoft SQL Server, etc.), but the following code should get you headed in the right direction... You'll probably need to modify the string concatenation to use some sort of cast or something, but, like I said, it's RDBMS-dependent.
Pseudocode:
select *
from have
where id in
(
select max(id) as topid
from have
group by case when aid<fid then aid+'|'+fid else fid+'|'+aid end
)
I am working on a PM system where I'd like to have the previous sent PMs for one conversation, listed above the last received PM. But my question is: how do I go about setting up such a table in a database? I toyed for a while about using an id for each specific conversation, but what would the source for that id be? I can't use auto increment (it seems), because I'm using it for the primary "id" column.
Or maybe there's a completely different way I can experiment with the already available columns (id, from, to, subject, message, sent, read, deleted); but how? Please help a lost man out.
You could add a origin_id column to your table that contains the id of the root/original message, or NULL if it's a new discussion (root).
Then you can get the root messages by filtering those than have origin_id = NULL and then group by origin_id to get the message thread.
Okay, so I have got it partly solved...
I used another table containing the one column which holds the subject of the PM. I also have a new column in the regular "pms" table that holds the same ID to be able to join the tables together.
However, when I select all the PMs to show them in the inbox, I have not found a way to group the conversations in order by if they're read or not. I'm currently using this SQL query:
SELECT *
FROM `pms`
JOIN `pm_conversations` ON (pms.ConvID = pm_conversations.ID)
WHERE pms.To='username'
GROUP BY pm_conversations.ID
ORDER BY pms.ID
I came up with this:
SELECT MAX(pms.ID) as pmIDS,
pms.*,
pm_conversations.*
FROM `pms`
JOIN `pm_conversations` ON (pms.ConvID = pm_conversations.ID)
WHERE `To`='".$UserActive."'
GROUP BY pm_conversations.ID
ORDER BY pmIDS DESC