MySQL only one message (the latest) per user in my inbox - mysql

Please help me, I want to display only one message (the latest) for each user in my inbox.
So if I am exchanging messages with user1, user2, user3,
instead of showing all their messages in the inbox like this:
user2 - message 6
user3 - message 5
user2 - message 4
user1 - message 3
user1 - message 2
user1 - message 1
I only need to show in my inbox the latest message from each one of them like this.
user2 - message 6
user3 - message 5
user1 - message 3
Here are my tables.
+-----------------------------------------------------------------------------------+
| messages |
+-----------------------------------------------------------------------------------+
| message_ID | sender |receiver| date | subject | body | unread | delete1 | delete2 |
+-----------------------------------------------------------------------------------+
+---------------------+
| members |
+---------------------+
| id | username | ...
+----+----------+-----+
So far this is my query.
SELECT p.*, p.sender as sender, m.*
FROM messages p
LEFT JOIN members m ON p.sender=m.member_id
WHERE p.receiver='<CURRENT_USER>' AND delete2=0
GROUP BY p.sender ORDER BY p.date DESC
LIMIT 5

SELECT p.*, p.sender as sender, m.*
FROM `messages` p
INNER JOIN (SELECT sender,
MAX(message_ID) as last_message_id
FROM `messages`
WHERE receiver='<CURRENT_USER>' AND delete2=0
GROUP BY `sender`) t2 ON t2.sender = p.sender
AND t2.last_message_id = p.message_ID
LEFT JOIN members m ON p.sender = m.member_id
WHERE receiver='<CURRENT_USER>' AND delete2=0
ORDER BY p.date DESC
LIMIT 5

u can get it by different functions like
select MAX(message_id)
EDIT.
try this
SELECT p.*, p.sender as sender, m.*
FROM messages p
inner join (select max(message_ID) lates from messages)as max on
max.lates = p.message_ID
LEFT JOIN members m ON p.sender=m.member_id
WHERE p.receiver='<CURRENT_USER>' AND delete2=0
GROUP BY p.sender ORDER BY p.date DESC
LIMIT 5

Related

SQL inner join on two colums

If i had two database tables
users -> (id, username)
and
messages -> (msg_id, sender_id, rec_id, text)
and they both joind on users.id = messages.sender_id and also on users.id = messages.rec_id so how i can print out results as follow
msg_id | sender | reciver | text
------------------------------------
1 | david | michael | hello friend
2 | eva | robert | pick me up
I've try this
SELECT users.*, messages.*
FROM messages
INNER JOIN users
ON users.id = messages.sender_id
AND users.id = messages.rec_id
but it seems not working as i want .. so any idea
update i ment by it deosn't seems to be working, that it gives the sender and reciver name are the same which is wrong !!
msg_id | sender | reciver | text
------------------------------------
1 | david | david | hello friend
2 | eva | eva | pick me up
You probably want to join multiple times
SELECT users1.*, users2.*,messages.*
FROM messages
INNER JOIN users1
ON users1.id = messages.sender_id
INNER JOIN users2
AND users2.id = messages.rec_id
You need two joins:
SELECT m.*, us.username as sender_name, ur.username as receiver_nae
FROM messages m JOIN
users us
ON us.id = m.sender_id JOIN
users ur
ON ur.id = m.rec_id;
In your current condition, the user id is equal to both the sender and the receiver id, meaning you will only query messages someone sent himself - which is probably not what you want to achieve. Instead, you can join on users twice, once for the sender and once for the receiver:
SELECT m.msg_id, s.username AS sender, r.username AS receiver, m.text
FROM messages m
JOIN users s ON m.sender_id = s.id
JOIN users r ON m.rec_id = r.id

Setting a clause for cross join (sql)

I am looking to show a mutual friends function but my user friends list is stored on another table.
I want to know if it's possible to use the data of each row as a clause for join B
SELECT * FROM ( SELECT * FROM `users`) a
CROSS JOIN (SELECT COUNT(*) AS MUTUAL_FRIENDS
FROM `user_friends` WHERE `friend_to` = `a`.`userid`) b
ORDER BY `b`.`MUTUAL_FRIENDS` ASC
What I am looking to do is use the userid from users table as a clause for the join with:
`friend_to` = `a`.`userid`
Expected results:
+--------=+---------+-----------+--------------+
| userid | Username |Photo_URL |MUTUAL_FRIENDS|
+---------+---------+-----------+--------------+
1 Somename1 /image1.png 3
4 Somename4 /image4.png 2
2 Somename2 /image2.png 1
3 Somename3 /image3.png 0
5 Somename5 /image5.png 0
Friends table:
+--------=+---------+-----------+
| friend_id | userid |friend_to |
+---------+---------+-----------+
1 1 2
2 2 1
3 1 3
4 3 1
5 1 4
6 4 1
Users Table
+--------=+---------+-----------+
| userid | Username |Photo_URL |
+---------+---------+-----------+
1 Somename1 /image1.png
2 Somename2 /image2.png
3 Somename3 /image3.png
4 Somename4 /image4.png
5 Somename5 /image5.png
Or am I doing this totaly wrong?
Here is one approach.
With CROSS JOIN
SELECT u.userid,u.Username,u.Photo_URL,IFNULL(Num,0) MUTUAL_FRIENDS
FROM Users u
LEFT JOIN (SELECT userid, COUNT(*) Num
FROM (SELECT a.userid
FROM Friends a
CROSS JOIN Friends b
WHERE a.userid = b.friend_to and a.friend_to = b.userid) r
GROUP BY userid) k ON u.userid = k.userid
ORDER BY MUTUAL_FRIENDS DESC, u.userid
Without CROSS JOIN
SELECT u.userid,u.Username,u.Photo_URL,IFNULL(Num,0) MUTUAL_FRIENDS
FROM Users u
LEFT JOIN (SELECT userid, COUNT(*) Num
FROM (SELECT a.userid
FROM Friends a, Friends b
WHERE a.friend_to = b.userid and b.friend_to = a.userid) r
GROUP BY userid) k ON u.userid = k.userid
ORDER BY MUTUAL_FRIENDS DESC, u.userid
I will try to explain little by little and please correct me if there is error.
The condition a.friend_to = b.userid and b.friend_to = a.userid is
used to select only mutual friend. Then if a user has this kind of
"mutual connection," the corresponding userid will appear once.
Get the count along with the userid.
Left join the userid and count table.
Result
userid Username Photo_URL MUTUAL_FRIENDS
1 Somename1 /image1.png 3
2 Somename2 /image2.png 1
3 Somename3 /image3.png 1
4 Somename4 /image4.png 1
5 Somename5 /image5.png 0
Given the data, user1 is mutual friend of user2, user3 and user4. User2 is only mutual friend of user 1 and so as user 3 and user4.
With CROSS JOIN SQL Fiddle
Without CROSS JOIN SQL Fiddle

Join users table with last conversation query

I need to join user info table with chat messages query for last reply.
Chat table
mid | sender | receiver| text | created
1 | chrys | Paul| Hello | 2015-12-08 20:00
2 | chrys2 | Chrys | Hey | 2015-12-08 20:10
For the last reply result i am using that script:
mysql_query("
select *
from
chat
join
(select user, max(created) m , COUNT(*) AS msgCount
from
(
(select mid, receiver user, created
from chat
where sender='$login_session' )
union
(select mid, sender user, created
from chat
where receiver='$login_session')
) t1
group by user) t2
on ((sender='$login_session' and receiver=user) or
(sender=user and receiver='$login_session')) and
(created = m)
order by created desc
");
My problem is that i can't figure out how to join a user info table like the following:
id | username | photo_url | age | etcetera.....
Some ideas?
All i need is to get infos about users wich are sendind messages like photo, age from the users_info table.
As per your query, you are trying to get last chat message sent or received for the logged in user.
For that,
select c.*
from chat c
join users u on u.id = c.receiver_id or u.id = c.sender_id
where u.id = 'SESSION.User.Id'
order by c.id desc
Meanwhile i found the answer. Here it is:
select c.*, u.photo
from chat c
join users u on u.username = c.sender
WHERE (sender = '$login_session' AND receiver = '$uid') OR
(sender = '$uid' AND receiver = '$login_session')

MySQL query for on user to list of users

My message system is based on message, threads, and participant
a message created by a user is linked to a thread
two participants (or more) are linked to a thread
each participant is linked to one user
I got this request. It give me the number of message a user has received (= number of message where the user is not the creator)
I count all messages created in a list of threads where the user is not the creator.
I got the list of threads by find all thread_id where my user participant is linked
SELECT COUNT(m.id)
FROM message m
INNER JOIN message_thread t ON m.thread_id = t.id
WHERE m.created_by_id != :userId
AND t.id IN (
SELECT t2.id
FROM message_thread t2
INNER JOIN message_participants p ON p.thread_id = t2.id
WHERE p.user_id = :userId
)
So that is for one uniq user.
+-------------+
| count(m.id) |
+-------------+
| 7 |
+-------------+
I'm trying to do the same, but with severals users, and get for each of them, the number of message they received
+---------+-------------+
| User id | count(m.id) |
+---------+-------------+
| 12645 | 1 |
| 985 | 5 |
| 8956 | 15 |
| 37856 | 2 |
+---------+-------------+
I tried to do that with more JOIN instead of t.id IN ( and group by the result, but without success...
One method is a brute force method, where you bring in all the users you care about and use that information for the processing:
SELECT u.userid, COUNT(m.id)
FROM message m INNER JOIN
message_thread t
ON m.thread_id = t.id CROSS JOIN
(SELECT 12645 as userid UNION ALL
SELECT 985 UNION ALL
SELECT 8956 UNION ALL
SELECT 37856
) u
WHERE m.created_by_id <> u.userId AND
t.id IN (SELECT t2.id
FROM message_thread t2 INNER JOIN
message_participants p
ON p.thread_id = t2.id
WHERE p.user_id = u.userId
)
GROUP BY u.userId;
If you wanted to do this for all users, I would recommend a different approach: count all the messages a user participates in and subtract out the ones where s/he is the creator:
SELECT p.userid,
COUNT(DISTINCT CASE m.created_by_id <> p.userId THEN m.id END) as numMessages
FROM message m INNER JOIN
message_thread t
ON m.thread_id = t.id INNER JOIN
message_participants p
ON p.thread_id = t.id
GROUP BY p.userid;
You should use a group by
SELECT message_thread.your_user_id COUNT(m.id)
FROM message m
INNER JOIN message_thread t ON m.thread_id = t.id
WHERE m.created_by_id != :userId
AND t.id IN (
SELECT t2.id
FROM message_thread t2
INNER JOIN message_participants p ON p.thread_id = t2.id
)
group by message_thread.your_user_id

how to write the sql statement?

I have 3 tables as follows in my database. this is used to a application just like foursqure. i need help with the problem of writing the sql statement i have asked in the bottom of this.
thank you
user_details
user_id | fname
----------------
1 | Losh
8 | Dush
9 | Rosh
10 | NELL
friends
user_idf |user_idff
----------------
1 | 8
8 | 9
10 | 1
Check_in
check_in_id |user_id | place | date
--------------------------------------------
1 | 8 | Hotel | 01/01/2012
2 | 9 | Home | 05/01/2012
3 | 1 | Junction | 08/01/2012
4 | 1 | Rest | 11/01/2012
5 | 9 | Hotel | 15/01/2012
6 | 8 | Home | 15/01/2012
i get the user's who are friends with 8 and user 8 details AND the check in places as follows
SELECT a.`user_id`, a.`fname` , b.*
FROM `user_details` a, `check_in` b
WHERE (b.user_id = 8
OR b.user_id in (select user_idf from friends where user_idff = '8' union select user_idff from friends where user_idf = '8')) AND b.user_id = a.user_id
how do i write the sql to select who are friends with 8 and user 8 details AND the last check in place of those users
explanation::
i seeks for a answer such as
user id name place date
1 LOSH Rest 11/01/2012
8 DUSH HOME 15/01/2012
9 ROSH HOTEL 15/01/2012
Join it to the table returned by:
(SELECT `user_id`, `place` FROM Check_in GROUP BY user_id ORDER BY `date` DESC)
That should give you one entry per user, and since it's sorted in reverse by date, that entry should be the most recent.
But when i group by it gives me the first dates not the latest date
How about this:
(SELECT user_id, place
FROM (SELECT * FROM Check_in ORDER BY `date` DESC) tmp
GROUP BY user_id)
SELECT user_id, fname, c.place
FROM user_details u
INNER JOIN (SELECT IF(user_idff = 8, user_idf, user_idff) AS user_id
FROM friends
WHERE (user_idff = 8 OR user_idf = 8)
) f
ON u.user_id = f.user_id
LEFT JOIN (SELECT c1.user_id, place
FROM Check_in c1
LEFT JOIN Check_in c2
ON c1.user_id = c2.user_id AND
c1.date < c2.date
WHERE c2.date IS NULL
) c
ON u.user_id = c.user_id;
This doesn't break ties but it's a straighforward way of answering your question.
EDIT
I just re-read you question and I see that you want user 8 info also. It's not clear whether you want user 8 as a separate row or with info in line with the friends' rows.
select *
from
friends as f inner join check_in as ci on ci.user_id = f.user_idff
inner join user_details as ud on ud.user_id = f.user_idff
inner join user_details as ud8 on ud8.user_id = f.user_idf
where
f.user_idf = 8
and date = (
select max(date)
from friends as f2 inner join check_in as ci on ci.user_id = f2.user_idff
where f2.user_idf = f.user_idf
)
EDIT 2
You request may be a small bit unclear about determining which check-in location to return. Use this option if you want the latest location of each friend individually. The first query finds the most recent location among all friends. Obviously these are two variations on an identical theme.
select *
from
friends as f inner join check_in as ci on ci.user_id = f.user_idff
inner join user_details as ud on ud.user_id = f.user_idff
inner join user_details as ud8 on ud8.user_id = f.user_idf
where
f.user_idf = 8
and date = (
select max(date)
from check_in as ci
where ci.user_id = f.user_idff
)
(SELECT a.user_id, a.place, b.fname, a.date, a.time, a.check_in_id
FROM (SELECT * FROM check_in ORDER BY date DESC) as a, user_details as b
WHERE a.user_id = b.user_id AND (a.user_id in (select user_idf from friends where user_idff = '8' union select user_idff from friends where user_idf = '8') OR a.user_id = 8)
GROUP BY a.user_id)
above query gave me the required answer.
thank you all for the help given