So hopefully the question is not asked, but I didn't find it.
My example table looks like this: https://imgur.com/a/BBykp
For my SQL I know for example the user ID of 1 and I want to show the Inbox of my Messanger for that I need to know if User ID 1 received a message or was the sender of a message.
For example:
sender_id receiver_id
1 2
3 1
1 4
12 1
Should give me four Inbox results for ID 1.
So I currently stuck with
SELECT * FROM chats AS tm
WHERE tm.id IN
(SELECT MAX(id) FROM chats WHERE sender_id = 1 OR receiver_id = 1 GROUP BY receiver_id)
This gets me:
https://imgur.com/a/P665T
You'll see that I don't need ID 2, but I care for ID 3, because it's the latest message of that conversation.
So how can I decide with SQL that I want the latest of sender_id 1 or receiver_id 1?
Thank you!
One option uses a least/greatest trick:
SELECT t1.*
FROM chats t1
INNER JOIN
(
SELECT
LEAST(sender_id, receiver_id) AS sender_id,
GREATEST(sender_id, receiver_id) AS receiver_id,
MAX(updated_at) AS max_updated_at
FROM chats
GROUP BY
LEAST(sender_id, receiver_id),
GREATEST(sender_id, receiver_id)
) t2
ON LEAST(t1.sender_id, t1.receiver_id) = t2.sender_id AND
GREATEST(t1.sender_id, t1.receiver_id) = t2.receiver_id AND
t1.updated_at = t2.max_updated_at;
Demo
SELECT * FROM chats AS tm WHERE tm.id IN (SELECT MAX(id) FROM chats
WHERE sender_id = 1 OR receiver_id = 1 GROUP BY receiver_id)
You could try with Top(1) like this
SELECT id FROM chats
WHERE sender_id = 1 OR receiver_id = 1 ORDER BY ID DESC
LIMIT 1
This is the last row in chats witch contains a sender or reciver with id 1
Is a first a aproximation (It´s suboptimal)
Related
I have a chat row and I want to fetch one row out of multiple (last row preferable).
The database looks like this...
I need to fetch the last conversation (DISTINCT) between a user and others and display in a record set
One result per user we have had conversation with.
This is what I have at the moment:
select sender_id,receiver_id,message, count(*)
from chat
where (`sender_id` = '5' OR `receiver_id` = '5')
group by receiver_id, sender_id
HAVING count(*) > 1;
Thanks.
For user 5 you want the last row per other user. The other user is:
case when sender_id = 5 then receiver_id else sender_id end
The complete query:
select *
from chat
where (sender_id = 5 or receiver_id = 5)
and (case when sender_id = 5 then receiver_id else sender_id end, message_date_time) in
(
select
case when sender_id = 5 then receiver_id else sender_id end as other_user,
max(message_date_time)
from chat
where sender_id = 5 or receiver_id = 5
group by case when sender_id = 5 then receiver_id else sender_id end
);
As of MySQL 8.0 you can use ROW_NUMBER instead to rank your records per other user by datetime.
select *
from
(
select
chat.*,
row_number() over (
partition by case when sender_id = 5 then receiver_id else sender_id end
order by message_date_time desc, id desc) as rn
from chat
where sender_id = 5 or receiver_id = 5
) ranked
where rn = 1;
I have a question with SQL.
I have 3 tables, messages, payments and reports.
I want to get all events from a user from every table in one query, so this is wat I like to get:
SELECT * FROM messages WHERE receiver_id = 10
SELECT * FROM payments WHERE client_id = 10
SELECT * FROM reports WHERE receiver_id = 10
But in 1 query.
Is this possible?
Table structures:
- messages
id
sender_id
receiver_id
type
text
created_at
updates_at
- payments
id
user_id
client_id
method
cost
status
text
created_at
updated_at
- reports
id
sender_id
receiver_id
text
created_at
updates_at
If there is no relationships between the 3 tables then you can just use UNION. It can be as simple as this:
SELECT receiver_id as event_id, event_name, event_description, event_timestamp FROM messages WHERE receiver_id = 10
UNION
SELECT client_id as event_id, event_name, event_description, event_timestamp FROM payments WHERE client_id = 10
UNION
SELECT receiver_id as event_id, event_name, event_description, event_timestamp FROM reports WHERE receiver_id = 10
This assumes there is a common set of columns across all tables that you are interested in. If however the columns have differing names but contain the same data (and datatypes), then you can use AS to rename the columns in the query to achieve the UNION
SELECT receiver_id as event_id, col1 as event_name, col2 as event_description, col3 event_timestamp FROM messages WHERE receiver_id = 10
UNION
SELECT client_id as event_id, col_a as event_name, col_b as event_description, col_c event_timestamp FROM payments WHERE client_id = 10
UNION
SELECT receiver_id as event_id, col_x as event_name, col_y as event_description, col_z event_timestamp FROM reports WHERE receiver_id = 10
Keep in mind that UNION will eliminate duplicate rows in your dataset. If this is not the behavior that you want then use UNION ALL instead (it will not eliminate duplicates).
Also keep in mind that if you column datatypes are not the same across the table then you will have to cast them to a common type. Casting is highly dependent of your DBMS so make sure you use the correct methods to do so.
Its fairly straight forward providing receiver_id and client_id hold the same values:
SELECT * FROM `messages` LEFT JOIN `payments` ON
`messages`.`receiver_id` = `payments`.`client_id` LEFT JOIN `reports`
ON `messages`.`receiver_id` = `reports`.`receiver_id`
I dont really understand what you want, do you want to get all the data in 1 query, or do you need joins with them?
If you want all the data in one table you can just do this i think:
SELECT * FROM messages as M, payments as P, reports as R
WHERE M.receiver_id, P.client_id, R.receiver_id = 10
Else you need to show us some more details about the relationship
You can use Union or Union All to concatenate the results sets of the 3 queries. However all 3 tables must have the same amount of columns for it to work. Post your tables structure for a more exact solution.
SELECT * FROM messages WHERE receiver_id = 10
Union All
SELECT * FROM payments WHERE client_id = 10
Union All
SELECT * FROM reports WHERE receiver_id = 10
I am making a query in which i want the job ids to be grouped but i want the latest timestamp row in the result which is not happening
Here is the SQL fiddle
http://sqlfiddle.com/#!9/de8769
The normal view for table is
The output after using this query i made
SELECT
DISTINCT(user_id),
job_id,
message,
receiver_id,
parent,
type,
id as id FROM ai_ms_messages
WHERE (receiver_id = '7' OR user_id = '7') AND type<>0 AND type<>2 group by job_id
ORDER BY max(timestamp) DESC
But as you can see its taking the value of id as 3 for job_id 11 but it should have taken the value 5 (as that is latest for job_id 11) and also the order is wrong. Since job_id 11 is latest not job_id 12. Is there any way to achieve this ?
The query would be:
select
distinct(m1.user_id),
m1.job_id,
m1.message,
m1.receiver_id,
m1.parent,
m1.type,
m1.id as id from ai_ms_messages as m1
where m1.type<>0 and m1.type<>2
and m1.timestampt = (select max(m2.timestamp) from ai_ms_messages as m2 where m2.job_id = m1.job_id)
As per your query you are looking for data for receiver_id = '7' and for id =5 , receiver_id = '6' , so this is not in your query output.
Just remove where condition, or check data as per condition only.
GROUP BY groups on the first matching result it hits.
So, its preferable this method as the subquery.
SELECT *
FROM (
SELECT DISTINCT (
user_id
), job_id, message, receiver_id, parent,
TYPE , id AS id
FROM ai_ms_messages
WHERE (
receiver_id = '7'
OR user_id = '7'
)
AND TYPE <>0
AND TYPE <>2
ORDER BY TIMESTAMP DESC
) AS sub
GROUP BY job_id
Have a table for chat where I collect user_from, user_to and other non important stuffs for the example.
Want to get user_id's for all the users related in conversation (with where clause for current user_id).
In the example below I'm trying to search all the users where user_id=1 exist, but I know that doesn't work and don't know how to make it works.
SELECT *
FROM messages M
WHERE M.user_from="1" OR M.user_to="1"
GROUP by m.user_from, m.user_to
If in table are rows (below). Actually I want to receive finally array([0]=>2, [1]=>4), because user_id=1 have conversation only with user_id=2 and user_id=4
user_from | user_to
1 2
1 2
2 1
1 4
3 2
Probably I have to use Select in the Select or use anykind of Case When Then, but have no idea how to loop it correctly
RESOLVED WITH ORDERING BY LAST MSG_ID!!!
SELECT (IF( user_from = 1, user_to, user_from )) as user_id
FROM messages
WHERE `user_from` = 1 OR `user_to` = 1
GROUP BY user_id
ORDER BY MAX(msg_id) DESC
select user_to as user_id
from messages
where user_from = 1
union
(select user_from as user_id
from messages
where user_to = 1)
edited on suggestion from #Анжел Миленов - (I do not personally know why the brackets make a difference in mySql)
this is my conversation table:
conversationID || userID
1 || 1
1 || 2
2 || 1
2 || 2
2 || 3
as you can see each conversation can contain 2 users or more.
I am trying to get the id of the conversation that only 2 users are there.
ie conversation that contains only users 1 & 2, the answer is conversation 1.
but how do I get it?
This will select all conversations that have users 1 or user 2, or both, but no one else:
select conversationID
from conversations
group by conversationID
having count(*) = count(case when userID in (1,2) then 1 end)
If you also want all conversations that have exactly user 1 and 2, and no one else, you also have to add an and condition:
select conversationID
from conversations
group by conversationID
having count(*) = count(case when userID in (1,2) then 1 end)
and count(*) = 2 -- number of elements in set
If userID can be duplicated, it's also better to use distinct:
select conversationID
from conversations
group by conversationID
having
count(distinct userID) = count(distinct case when userID in (1,2) then userID end)
and count(distinct userID) = 2 -- number of elements in set
You should use having clause. Assuming that ( conversationID, userID ) is PK or AK, your query is:
select conversationID
from your_Table
group by conversationID
having count( * ) = 2
Edited Joined with 1,2 user conversations, this is the index friendly approach with out correlate subquery and without function by row.
select t1 conversationID
from your_Table t1
inner join
( select distinct conversationID
from your_Table
where userId in (1, 2)
) t2
on t1.conversationID = t2.conversationID
group by t1.conversationID
having count( distinct t1.userId ) = 2
Hope this helps you,
select conversationID from conversation
group by ConversationID having count(distinct UserID)=2;
sqlfiddle demo