I have table for messages which contains id, sender_id, receiver_id, message and conversation_id
(I connected them by conversation_id, which they make by sending first message and if someone is replying, first he search conversation_id from messages where he is receiver and guy where is he replying is sender and by that send message with same conversation_id)
Now in messages list I want to output one just one last row per different conversation_id where sender_id='$my_id' OR receiver_id='$my_id'
I am using DISTINCT but I get all rows always as output:
SELECT DISTINCT conversation_id, sender_id, message
FROM messages
WHERE receiver_id='$my_id'
ORDER BY id DESC
try this
SELECT id,conversation_id, sender_id, receiver_id, message FROM message WHERE receiver_id='$my_id' GROUP BY `conversation_id` ORDER BY id DESC LIMIT 1
Please give the following query a try:
SELECT
M.*
FROM messages M
INNER JOIN
(
SELECT
MAX(id) AS last_id_of_conversation,
conversation_id
FROM messages
GROUP BY conversation_id
) AS t
ON M.id = last_id_of_conversation
Explanation:
SELECT
MAX(id) AS last_id_of_conversation,
conversation_id
FROM messages
GROUP BY conversation_id;
This inner query will generate an output where there will be one row for each conversation_id along with the last id value (or max id) of the conversation.
Later make an inner join between your main table (messages) and the result returned by the inner query on matching id. I hope id is primary key. If so, then the above query ensures to bring a single row (more specifically the row having the last message) for each conversation.
EDIT:
SELECT
M.*
FROM messages M
INNER JOIN
(
SELECT
MAX(id) AS last_id_of_conversation,
conversation_id
FROM messages
WHERE sender_id = ? OR receiver_id = ?
GROUP BY conversation_id
) AS t
ON M.id = last_id_of_conversation
Related
I've got my MySQL query below:
select * from messages
where id in (select max(id) from messages group by Name)
Why does this query not work?:
select * from messages
where id in (select max(id) from messages where field <> 'value' group by Name)
It would be helpful to know what you mean by "doesn't work" - for example, whether you get an error or whether it produces unexpected results. However, going by your comment, and assuming you define "last item sales" by the maximum ID per user, I would recommend JOINing your table to a subquery that selects the maximum ID per user. For example, given the sample sales data set mentioned in your comment, you could write a query like so:
select s.*
from sales s
join (
select user_name, max(id) as max_id
from sales
where sale_item <> 'Ship'
group by user_name
) q
on q.user_name = s.user_name
and q.max_id = s.id
I have created a SQL Fiddle demonstrating the output of the query.
I would like to select data from a table like this (the table name is conversations_users) :
I would like to be able to retrieve a conversation ID that includes only two users. As instance, if I search a conversation specific to users 1 and 3 the conversation number 6 should be the unique result, because the conversation 5 also includes user 2.
I have tried to perform a request like
SELECT * FROM conversations_users AS table1 JOIN
conversations_users AS table2 ON
table1.conversation_ID = table2.conversationID
WHERE table1.userID = 3 AND
table2.userID = 1
But it returns both conversations 5 and 6. How can I fix that ?
Thank you in advance,
Pierre
Add the ON clause:
SELECT * FROM conversations_users AS table1 JOIN
conversations_users AS table2
ON table1.conversation_ID = table2.conversation_ID
WHERE table1.userID = 3 AND
table2.userID = 1
Update:
To get only coversations, where only 1 and 3 are involved, you can use having clause:
SELECT table1.conversation_ID FROM conversations_users AS table1 JOIN
conversations_users AS table2
ON table1.conversation_ID = table2.conversation_ID
WHERE table1.userID = 3 AND
table2.userID = 1
Group by table1.conversation_ID
having Count(*) = 2
The query you need looks like:
SELECT conversation_ID, GROUP_CONCAT(DISTINCT userID ORDER BY userID) as users
FROM conversations_users
GROUP BY conversation_ID
HAVING users = '1,3'
The GROUP BY clause groups the rows having the same conversation_ID and from each group it generates a new record that contains the conversation_ID and the distinct values of userID, in ascending order, concatenated with comma (,).
The HAVING clause keeps only those records that have '1,3' in the column users computed by the GROUP BY clause.
The query produces the output you need but it is not efficient because it reads the entire table. It could be more efficient by picking first the conversations of users 1 and 3 and then applying the above only to them.
It looks like this:
SELECT conversation_ID, GROUP_CONCAT(DISTINCT userID ORDER BY userID) as users
FROM (
SELECT *
FROM conversations_users
WHERE userID in (1, 3)
) conversations
GROUP BY conversation_ID
HAVING users = '1,3'
In order to work faster than the previous query, the conversations_users must have an index on the userID column.
If you want to restrict to those conversations which involve exactly n number of users. I think below generic query should work. Replacing 'n' as per requirement.
select *
from conversations_users
where conversation_id IN (select conversation_id
from conversations_users
group by conversation_id
having count(userid) = 2)
Thanks,
Amitabh
The inner select grabs all conversationIDs with other users than 1 or 3
the outer select (with distinct) collects all conversations wich are NOT in this subset
SELECT DISTINCT conversationID
FROM conversations_users t1
WHERE conversationID NOT IN ( SELECT conversationID
FROM conversations_users
WHERE userID NOT in (1, 3)
)
You can use join with where condition in this case.
SELECT #, userid ,conversation_ID FROM user AS table1 JOIN
conversations_users AS table2
ON user_ID = conversation_ID
WHERE table1.userID = 3 AND
table2.userID = 1
Group by conversation_ID
You can apply suitable condition by where clause instead of group by
I am trying to get a list of users that I have interacted with in a messaging system:
TABLE:
messages: id, sender_id, recipient_id, message, date
SQL:
SELECT * FROM `messages`
WHERE
(`sender_id` = :user_id OR `recipient_id` = :user_id)
GROUP BY `sender_id`, `recipient_id`
ORDER by `date` DESC
This gives me multiple rows with mismatched sender / recipient id's
I think its the GROUP BY thats causing it by not sure how to fix it
EDIT: I only need 1 row per interaction ( hence the GROUP BY )
GROUP BY will combine all the rows with the same sender_id and recipient_id. Use a UNION to combine the two groups into one set of results:
SELECT correspondent, MAX(date) AS last_date
FROM (
SELECT sender_id as correspondent, date
FROM messages
WHERE recipient_id = :user_id
UNION ALL
SELECT recipient_id as correspondent, date
FROM messages
WHERE send_id = :user_id) x
GROUP BY correspondent
ORDER BY last_date DESC
I have three tables:
user: id, name
keyword: id, name
userkeyword: id, user_id, keyword_id
I want to execute query in following way:
Display those users whose keyword/s are matched with the login user's
keywords. In the order of maximum number of keyword matched user
should display first
e.g : If userA having 4 matched keywords, userB having 8, userC having 1, userD having 6 then the result should be in the order of,
userB
userD
userA
userC
For that I have done with this query (assume login user's id is 1):
select *
from user
where id IN (
select user_id
from userkeywords
where keyword_id IN (
select keyword_id
from userkeywords
where user_id=1)
group by user_id
order by count(keyword_id) desc)
AND id != 1
Here the result is getting perfect but the order is not correct. I have merged two queries in following manner"
select *
from user
where id IN (?)
AND id!=1
+
select user_id
from userkeywords
where keyword_id IN (
select keyword_id
from userkeywords
where user_id=1)
group by user_id
order by count(keyword_id) desc
Second query returns user_id in correct order but when I merged both queries, order was changed (wrong).
Hope I have mentioned my query properly with enough detail.
A subquery returns an unordered set, so the order by in a subquery only matters for its limit clause, if there is any. Any database other than MySQL would give an error message for a purely decorative sort order.
There's no way to sort on a column that only exists in the where clause. You'd have to rewrite the query. One option is to replace your in conditions with joins:
select uk2.name
from userkeywords uk1
join userkeywords uk2
on uk1.keyword_id = uk2.keyword_id
and uk1.user_id <> uk2.user_id
join user u2
on u2.id = uk2.user_id
where uk1.user_id = 1
group by
uk2.name
order by
count(*) desc
This should do it.
select uk.user_id, u.name
from userkeywords uk
left join user u on u.id = uk.user_id
where uk.keyword_id IN (
select keyword_id
from userkeywords
where user_id=1)
group by uk.user_id
order by count(uk.keyword_id) desc) AND uk.user_id != 1
Also, JOIN provides better performance.
I would use an inner join to select the correct rows:
SELECT *
FROM user
INNER JOIN (
SELECT * FROM userkeyword
WHERE keyword_id IN (
SELECT keyword_id
FROM userkeyword
WHERE user_id=1
)
) uk
ON user.id = uk.user_id
GROUP BY u.id
ORDER BY count(*) DESC;
SELECT * FROM(
SELECT c_id, user_id, message, state, time FROM message
WHERE receive=1
ORDER BY message_id DESC
)AS t GROUP BY c_id
I have mysql statement can fetch out last message for user.
however i need to join the user table, so i can fetch out the sender's name
LEFT JOIN user ON user.user_id=message.user_id
How to achieve this?
//user
user_id name
//conversation
c_id user_id
//message
m_id c_id user_id(sender) receive message state time
SELECT * FROM (
SELECT c_id, user_id, message, state, time
FROM message
WHERE receive=1
ORDER BY message_id DESC) AS t
LEFT JOIN user ON user.user_id=t.user_id
GROUP BY c_id
P.S. check if user.user_id exists.