Sql statement with expression in group by - mysql

I have a question about one sql statement for my mysql db. I have a table with the following columns :-
sender_id | receiver_id | content | dateAndTime
As you understand I would like to implement sending messages between users. I want to select the last message(doesn't matter sent or received) with every user. Something like the messages in facebook. I guess that I should use expression in group by if it is possible but I would like to see your opinion how I should do it. Thanks!

For This kind of purpose, your field dateAndTime is must be date-time type.
SELECT * FROM TABLE ORDER BY dateAndTime DESC
You can retrieve latest data using this descending order.

Try this one
SELECT C.ID, T.content, T.dateAndTime FROM T JOIN
(
SELECT ID, MAX(dateAndTime) 'last' FROM
(
SELECT sender_id 'ID', content, dateAndTime FROM T
UNION
SELECT receiver_id 'ID', content, dateAndTime FROM T
) B
GROUP BY ID
) C
WHERE T.dateAndTime = C.last AND (T.sender_id = C.ID OR T.receiver_id = C.ID)

Assuming you have a 'users' table, and your stated table named 'mytable' you could:
select users.id,mytable.content, MAX(mytable.dateAndTime) as date
from users join mytable
on users.id = mytable.sender_id
or users.id = mytable.receiver_id
group by users.id, mytable.content, date
The max function will keep only the latest date from each group generated by the group by
EDIT: try this instead
select users.id, mytable.content, mytable.dateAndTime
from users join mytable
on users.id = mytable.sender_id
or users.id = mytable.receiver_id
where mytable.dateAndTime = (select max(t.dateAndTime) from mytable as t where t.receiver_id = users.id or t.sender_id = users.id)

Related

SELECT the last message of conversation - MySQL

I have query which looks like:
SELECT * FROM
( SELECT DISTINCT CASE
WHEN user1_id = 1
THEN user2_id
ELSE user1_id
END userID,conversationId
FROM conversations
WHERE 1 IN (user2_id,user1_id))dt
INNER JOIN users on dt.userID = users.id
It returns conversationId and information about user from users table. I would like to also add the last message (the one with biggest messageId) from message table on base of conversationId. The last thing would be to sort all the results by messageId
I tried to use another INNER JOIN which looked like :
INNER JOIN message on dt.conversationId = message.conversationId
Its adding messages to the result but I would like to get only the last one (the one with highest messageId as mentioned). I guess I would have to implement MAX somehow but I dont have idea how. The same thing with sorting all result by messageId so results with the biggest messageId would be first.
Thanks for all suggestions.
You can get the highest messageId for the conversation in a corelated subquery and use it for your join condition:
INNER JOIN message m
on m.conversationId = dt.conversationId
and m.messageId = (
SELECT MAX(m1.messageId)
FROM message m1
WHERE m1.conversationId = dt.conversationId
)
So the solution for eveything was following query
SELECT * FROM
( SELECT DISTINCT
CASE
WHEN user1_id = 1
THEN user2_id
ELSE user1_id
END userID,conversationId
FROM conversations
WHERE 1 IN (user2_id,user1_id))dt
INNER JOIN users on dt.userID = users.id
INNER JOIN message m on m.conversationId = dt.conversationId and m.messageId = (SELECT MAX(m1.messageId)
FROM message m1 WHERE m1.conversationId = dt.conversationId)
ORDER by m.messageId DESC

How to select single rows using MAX and GROUP BY on non-uniqe field in MySQL?

I came across this very simple case where I need to select a list of conversations from Conversations table along with latest message from Messages table - which has non-uniqe dateCreated field.
After long research I came up with this query:
SELECT
Conversations.id,
dateCreated,
`name`,
lastMessageId,
lastMessageDate,
lastMessagePayload
FROM Conversations
LEFT JOIN (
SELECT
id AS lastMessageId,
m1.conversationId,
payload AS lastMessagePayload,
m1.dateCreated AS lastMessageDate,
FROM Messages AS m1
INNER JOIN (
SELECT conversationId, MAX(dateCreated) AS mdate FROM Messages GROUP BY conversationId
) AS m2
ON m1.conversationId = m2.conversationId AND m1.dateCreated = m2.mdate
) AS msg2
ON msg2.conversationId = Conversations.id
ORDER BY dateCreated DESC
Query works well but if two latest messages in same conversation have exact same dateCreated field this query would then output two conversations with same id but different lastMessage... row of fields.
I just couldn't find a way to get around this problem as main problem is when you do GROUP BY a field and MAX on another non-uniqe field then you can't get out always only one row out.
Any idea how to get list of unique conversations with latest message (any message of the two if they have the same date)?
Use row_number()!
select c.*, m.* -- or whatever columns you want
from conversations c left join
(select m.*,
row_number() over (partition by m.conversationid order by m.dateCreated desc, m.id desc) as seqnum
from messages m
) m
on m.conversation_id = c.id and
m.seqnum = 1;
MySQL 5.x version...
Use a correlated sub-query to get the latest message id (for a given conversation), using ORDER BY and LIMIT 1
SELECT
Conversations.Conversations.id,
Conversations.dateCreated,
Conversations.`name`,
Messages.id AS lastMessageId,
Messages.payload AS lastMessagePayload,
Messages.dateCreated AS lastMessageDate,
FROM
Conversations
LEFT JOIN
Messages
ON Messages.id = (
SELECT lookup.id
FROM Messages AS lookup
WHERE lookup.conversationId = Conversations.id
ORDER BY lookup.dateCreated DESC
LIMIT 1
)
ORDER BY
Conversations.dateCreated DESC
In the event of two messages having the same date, the message you get is non-deterministic / arbitrary.
You could, if you wanted, therefore change it to get the highest id from the most recent date...
ORDER BY lookup.dateCreated DESC, lookup.id DESC
LIMIT 1

How to show username from another table on the basis of max id in sqql

I am trapped in a sql query, I know it may be common but not getting any proper solution.
From my table messages, I have successfully fetch max id by joining from and to columns, now what I am trying to do is, I want to pull the name of that max id from another table naming users,
Here is my working query to find max id,
select m.*
from messages m
where m.id in (select max(m.id) as max_id
from messages m
where m.`from` = 7
or m.`to` = 7
group by least(m.`to`, m.`from`), greatest(m.`to`, m.`from`))
I have tried something like this but it matches name with from column of messages table.
select messages.*, users.name
from messages
left join users on messages.`from` = users.id
where messages.id in (select max(id) as max_id
from messages
where `from` = 7
or `to` = 7
group by least(`to`, `from`), greatest(`to`, `from`))
I want that name will be shown according to max id that I am getting.
columns of messages table : id , from, to, created_at
columns of users table : id, name, email, created_at
Please help me out,
One method is to join, but only to the column that is not 7:
select m.*, u.name
from messages m join
users u
on u.id in (m.`from`, m.`to`) and u.id <> 7
where m.id in (select max(m.id) as max_id
from messages m
where 7 in (m.`from`, m.`to`)
group by least(m.`to`, m.`from`), greatest(m.`to`, m.`from`)
);

How to pass parent field in sub union query

I've this query and its giving an error that unknown U.UserID column in where clause but I can't see any error in it as my Users table instance is U
SELECT GROUP_CONCAT(U.UserID),
(
SELECT COUNT(DISTINCT(UserID))
FROM (
SELECT FriendID as UserID
FROM Friends
WHERE UserID=U.UserID AND Status=1
UNION All
SELECT UserID
FROM Follow
WHERE Type='user' AND TypeEntityID=U.UserID
) tbl
) as NoOfFriendsFollow
FROM `Users` `U`
WHERE `U`.`UserID` IN('1')
LIMIT 10
Any solution for this query or let me know where I'm wrong
SELECT GROUP_CONCAT(UserID),
(
SELECT COUNT(DISTINCT(UserID)) FROM
(
SELECT FriendID as UserID FROM Friends F
INNER JOIN Users U ON U.UserID=F.FriendID
WHERE F.Status=1
UNION All
SELECT FF.UserID FROM Follow FF
INNER JOIN Users U ON U.UserID=FF.UserID
WHERE Type='user' AND TypeEntityID=U.UserID
) tbl
) as NoOfFriendsFollow
FROM Users WHERE UserID IN('1') LIMIT 10;
Just try above code.
Hope this will helps.
Unfortunately, MySSQL does not permit you to use an outer table reference "two levels down". So you can do:
SELECT U.UserID,
(SELECT COUNT(DISTINCT UserID)
FROM (SELECT fr.FriendID as UserID, fr.FriendId as compareId
FROM Friends fr
WHERE fr.Status = 1
UNION All
SELECT f.UserID, f.TypeEntityID as compareId
FROM Follow f
WHERE f.Type = 'user'
) tbl
WHERE tbl.UserID = compareId
) as NoOfFriendsFollow
FROM Users U
WHERE U.UserID IN (1)
LIMIT 10;
Notes:
This moves the comparison into the middle subquery, so the query parses.
Presumably UserId is an integer. Only use single quotes for string and date constants.
The GROUP_CONCAT() doesn't make sense. It turns the query into an aggregation query that returns only one row.
I double the LIMIT is needed either. There should be one row per UserId.
Always use qualified column names when you have multiple tables in a query.

MySQL latest unique user chats not working

I'm trying to get latest created datetime for unique user_id. I've got below query but it does not seem to be working....It does not get the latest created time.
SELECT * FROM `chats`
WHERE receiver_id = 1
GROUP BY user_id
ORDER BY created DESC
Is there a reason why?
UPDATE:
Actually I found my answer myself. Please look below. I had to use INNER JOIN for nested searched and filtered result table then find using where clause of that result then left join on that table to get the data I needed!
SELECT c.*, users.username
FROM chats c
INNER JOIN(
SELECT MAX(created) AS Date, user_id, receiver_id, chat, type, id
FROM chats
WHERE receiver_id = 1
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 = 1
You should use a MAX aggregate function -
SELECT user_id, MAX(created) latest_datetime FROM chats
GROUP BY user_id;
Try this query, it will show all users and latest created datetime.