I have 2 mysql tables (Version Minor to MySql 8) in a simple chat app
Chat
id_chat
chat_name
1
My first chat
2
My Second Chat
And Chat_Message
id_chat_message
id_chat
message
date
1
1
How
03/Mar/2021
2
1
Are you
04/Mar/2021
3
2
This
05/Mar/2021
4
2
Is other
06/Mar/2021
How can I make a Query if I want to retrieve the last message for every chat?
The resultset should be
id_chat
chat_name
last_message
last_message_date
1
My first chat
Are you
04/Mar/2021
2
My Second Chat
Is other
06/Mar/2021
Thanks
After some tests I came with this, but I'm not 100% sure it works in all cases:
SELECT hc.id_chat, hc.chat_name, hcm.message as last_message, hcm.date as last_message_date from chat hc inner join (SELECT a.*
FROM chat_message a
INNER JOIN (
SELECT id_chat, MAX(date) date
FROM chat_message
GROUP BY id_chat
) b ON a.id_chat = b.id_chat AND a.date = b.date) hcm on hc.id_chat = hcm.id_chat group by hcm.id_chat;
Some inspiration came from SQL select only rows with max value on a column
On MySQL 8+, we can use ROW_NUMBER here:
WITH cte AS (
SELECT c.id_chat, c.chat_name, cm.message, cm.date,
ROW_NUMBER() OVER (PARTITION BY c.id_chat ORDER BY cm.date DESC) rn
FROM Chat c
INNER JOIN Chat_Message cm ON cm.id_chat = c.id_chat
)
SELECT id_chat, chat_name, message, date AS last_message_date
FROM cte
WHERE rn = 1;
On earlier versions of MySQL, we can join to a subquery which finds the latest chat message from the second table.
SELECT c.id_chat, c.chat_name, cm.message, cm.date AS last_message_date
FROM Chat c
INNER JOIN Chat_Message cm
ON cm.id_chat = c.id_chat
INNER JOIN
(
SELECT id_chat, MAX(date) AS max_date
FROM Chat_Message
GROUP BY id_chat
) t
ON t.id_chat = cm.id_chat AND t.max_date = cm.date;
Related
[DB Table]
SELECT b.first_name, b.last_name, a.pod_name, a.category, c.user_id,
SUM(IF(QUARTER(CURDATE())-1 OR (QUARTER(CURDATE())-2) AND a.user_id, 1, 0)) AS flag FROM kudos a
INNER JOIN users b ON a.user_id = b.id INNER JOIN users_groups c ON a.user_id = c.user_id
INNER JOIN groups d ON c.group_id = d.id WHERE a.group_name = 'G2' AND d.id IN (7,8,9,11,12,13,14,15,16,17,21,22,23,24,25,26,27,28)
AND QUARTER(CURDATE())-1 = a.quarter ORDER BY a.final_score+0 DESC
I need to get the user_ids of those users which are both in quarter 1 and 2 from table.
Tried above query but failed to get expected results.
Can someone please guide me on this?
if you only need user_id then you can do this :
select user_id
from tablename
where quarter in (1,2)
group by user_id
having count(distinct quarter) = 2
another way is to use window function, assuming you have one user id in each quarter:
select * from (
select * , count(*) over (partition by user_id) cn
from tablename
where quarter in (1,2)
) t where cn = 2
i want to display three replies from each user i have in my users table, so for instance if i have 3 users and each of them had replied to lets say 10 messages, i want my query to only retrieve 9 replies and not all of the replies in my messages_reply table.
heres what i tried:
$replyquery="select *
from messages_reply
LEFT JOIN users
ON messages_reply.from_id=users.id
GROUP BY messages_reply.id LIMIT 3";
i know that what i wrote means that bring me 3 replies only, so how do i bring 3 replies from each user in my users table?
In many databases, you can use row_number() for this:
select *
from (
select mr.*, u.*, row_number() over(partition by u.id order by mr.id desc) rn
from messages_reply mr
inner join users u on mr.from_id = u.id
) t
where rn <= 3
If you are running MySQL < 8.0, as I suspect from the lax use of group by in your query:
select mr.*, u.*
from messages_reply mr
inner join users u on mr.from_id = u.id
where mr.id >= (
select mr1.id
from messages_reply mr1
where mr1.from_id = u.id
order by mr1.id desc
limit 2, 1
)
This gives you the 3 message replies with the greatest id for each user.
Query not tested, just a concept
SELECT *
FROM users
LEFT JOIN (
SELECT *
FROM messages_reply
WHERE from_id = users.id
ORDER BY <your wanted order field> DESC
LIMIT 3) replies
ON users.id = replies.from_id
I got this MySQL query to output latest chat message a user with ID of 18 has had with other users. The query works until I add-in last JOIN, intended to calculate amount of unviewed msgs (unviewed_total). The error I get is 'column not found' for T2.rid1 and T2.rid2. Can't figure out how to refer these columns in a proper way.
SELECT T2.maxDate, T2.ava, T2.uname,chat.user_to,chat.user_from,chat.body,chat.request_id,chat.secondary_rid, T3.unviewed_total FROM
(SELECT T1.user2_id, users.uname, users.ava, max(cdate) maxDate, T1.rid rid1, T1.sec_rid rid2 FROM
(SELECT chat.user_to user2_id, max(msg_time) cdate,request_id rid,secondary_rid sec_rid
FROM chat WHERE chat.user_from=18
GROUP BY chat.user_to
union distinct
(SELECT chat.user_from user2_id, max(msg_time) cdate,request_id rid,secondary_rid sec_rid
FROM chat WHERE chat.user_to=18
GROUP BY chat.user_from)) T1
inner join users on (users.uid = T1.user2_id)
group by T1.user2_id
order by maxDate desc) T2
join chat on (T2.maxDate = chat.msg_time)
join (SELECT COUNT(viewed) unviewed_total FROM chat WHERE viewed='0' AND user_to=18 AND request_id IN (T2.rid1,T2.rid2)) T3
ORDER BY T2.maxDate DESC
The inner query of that join doesn't know about the table T2.
I suggest moving the join to the select statement.
Change
SELECT T2.maxDate, T2.ava, T2.uname,chat.user_to,chat.user_from,chat.body,chat.request_id,chat.secondary_rid, T3.unviewed_total FROM
to
SELECT T2.maxDate, T2.ava, T2.uname,chat.user_to,chat.user_from,chat.body,chat.request_id,chat.secondary_rid, (SELECT COUNT(viewed) unviewed_total FROM chat WHERE viewed='0' AND user_to=18 AND request_id IN (T2.rid1,T2.rid2)) unviewed_total
More about this technique here: https://www.essentialsql.com/get-ready-to-learn-sql-server-20-using-subqueries-in-the-select-statement/
I have this code:
SELECT a.id, a.to_id, a.from_id, a.seen, a.date, a.message
FROM `Chat_messages` a
INNER JOIN (
SELECT MAX( `id` ) AS id
FROM `Chat_messages` AS `alt`
WHERE `alt`.`to_id` =7
OR `alt`.`from_id` =7
GROUP BY `to_id` , `from_id`
)b ON a.id = b.id
returning:
So, I want to get conversations (sent and received messages) of an user and latest message of it.
Latest message works ok, but the problem is that I get 2 rows from messages received (#1 and #2) and 2 rows from messages sent (#3 and #4), but I only need 2 results, because there are 2 conversations.
The best way to pick out the row that holds the latest sent message and the row that holds the latest received message respectively, is using the row_number() window function. Unfortunately, MySql does not support window functions, so I think it's best to use two nested SELECT's:
SELECT z.id, max(z.to_id), max(z.from_id), max(z.seen), max(z.date), max(z.message)
FROM chat_messages z
LEFT JOIN
(SELECT x.from_id, max(date) date
FROM chat_messages x
GROUP BY x.from_id) f
ON z.from_id = f.from_id AND z.date = f.date
LEFT JOIN
(SELECT y.to_id, max(date) date
FROM chat_messages y
GROUP BY y.to_id) t
ON z.to_id = t.to_id AND z.date = t.date
GROUP BY z.id
I do not recommend using max on ID's if you care about correctness in the long run.
You can group by least(to_id, from_id), greatest(to_id, from_id) to make sure conversions between 2 people are merged:
SELECT a.id, a.to_id, a.from_id, a.seen, a.date, a.message
FROM `Chat_messages` a
INNER JOIN (
SELECT MAX( `id` ) AS id
FROM `Chat_messages` AS `alt`
WHERE `alt`.`to_id` =7
OR `alt`.`from_id` =7
GROUP BY least(`to_id` , `from_id`), greatest(`to_id` , `from_id`)
)b ON a.id = b.id
The title may be confusing, here is my schema
and here is the result of my query
how can i remove duplicates and just get the values highlighted, i am trying to order by message time
Regards
The following syntax will work in both SQL Server and MySQL:
SELECT c.ContactID, c.Name, m.Text, m.Messagetime
FROM Contacts c INNER JOIN
Messages m
ON c.ContactID = m.ContactID
WHERE NOT EXISTS (select 1
from messages m2
where m2.ContactId = m.ContactId and
m2.MessageTime > m.MessageTime
)
ORDER BY m.MessageTime desc;
Note that if you have duplicate most recent message times, then all will be returned.
One way in SQL-Server is using a ranking function like ROW_NUMBER:
WITH CTE AS
(
SELECT c.ContactID, c.Name, m.Text, m.Messagetime,
RN = ROW_NUMBER() OVER (PARTITION BY c.ContactID
ORDER BY m.MessageTime DESC)
FROM dbo.Contacts c
INNER JOIN Messages m ON c.ContactID = m.ContactID
)
SELECT ContadctId, Name, Text, Messagetime
FROM CTE
WHERE RN = 1