Select one record based on results from multiple rows - mysql

I have two tables:
| conversations | | conversation_participants |
------------------- ----------------------------------
| id | project_id | | id | conversation_id | user_id |
------------------- ----------------------------------
1 | 1 1 | 1 | 1
2 | 1 2 | 1 | 2
3 | 2 | 1
4 | 2 | 3
I need to select the conversation id that two users have in common for a specific project id
So in this example:
the conversation id that user_id 1 and user_id 2 have in common for project_id 1 is: 1
the conversation id that user_id 1 and user_id 3 have in common for project_id 1 is: 2
I need a query where I can give user_id a, user_id b, and project_id and get a conversation id in return.
I tried something like :
SELECT
c.id
FROM conversations c
JOIN conversation_participants p ON p.conversation_id = c.id
WHERE (p.user_id = ? AND c.project_id = ?)
OR (p.user_id = ? AND c.project_id = ?)
but of course this returns multiple rows and its probably wrong because in some cases it will return records with different conversation ids...
Help appreciated! Thanks!.

try this
SELECT
c.id
FROM conversations c
JOIN conversation_participants p ON p.conversation_id = c.id
JOIN conversation_participants p2 ON p2.conversation_id = p.conversation_id
WHERE c.project_id = ?
AND p.user_id = ? and p2.user_id = ?
you can give:
p.user_id = 1 --as user1
p2.user_id = 2 --as user2
c.project_id = 1
DEMO HERE

Related

Get list of groups user hasn't Joined, List of groups user didn't create

The user (Ben) has joined group 2 and group 3. How can I write this in a select query... I want to select from groups I haven't joined and groups I didn't create.
users_tbl table
user_id username
| 1 | ben
| 2 | betty
| 3 | tim
| 4 | jimmy
| 5 | sammy
user_groups table
user_id group_id
| 1 | 2
| 1 | 3
group_tbl table
group_id user_id
| 1 | 5
| 2 | 4
| 3 | 5
I am able to get the list of groups I didn't create using this query...
SELECT * FROM group_tbl LEFT JOIN users_tbl ON users_tbl.user_id = group_tbl.user_id WHERE group_tbl.user_id != ? ORDER BY RAND() LIMIT 10
How can I get the list of groups users hasn't joined?
You can do it if you do a LEFT join of group_tbl to users_tbl and return the unmatched rows of group_tbl:
SELECT g.*
FROM group_tbl g LEFT JOIN user_groups u
ON u.group_id = g.group_id AND u.user_id = 1
WHERE u.user_id IS NULL
Or with NOT EXISTS:
SELECT g.*
FROM group_tbl g
WHERE NOT EXISTS (
SELECT 1
FROM user_groups u
WHERE u.group_id = g.group_id AND u.user_id = 1
)
See the demo.
Results:
group_id
user_id
1
5

Get last Message Reply From Conversation

so I have two tables chats and chats_reply. The structure is the following.
chats
--------------------------------------------------
| chat_id | user_one | user_two | created_at
--------------------------------------------------
| 1 | 1 | 2 | something here
--------------------------------------------------
chats_reply
-------------------------------------------------------------------------
| chatReply_id | chat_id | user_id | reply | created_at
-------------------------------------------------------------------------
| 1 | 1 | 1 | Message 1 | something here
-------------------------------------------------------------------------
| 2 | 1 | 2 | Message 2 | something here
-------------------------------------------------------------------------
I'm having a bit of a problem with my query. Let's say my user_id is 1. I want to return a list of all my chats with the last message that was sent. I already have the query that lists all my chats, but it doesn't return the last message it return the first message of the conversation. This is my query:
SELECT
chats.chat_id,
chats.created_at AS ChatTime,
chats_reply.reply,
chats_reply.created_at AS ReplyTime,
chats_reply.status,
users.name,
users.last_name,
users.email
FROM chats
INNER JOIN chats_reply
ON chats.chat_id = chats_reply.chat_id
INNER JOIN users
ON users.user_id =
CASE
WHEN chats.user_one = '1'
THEN chats.user_two
WHEN chats.user_two = '1'
THEN chats.user_one
END
WHERE chats.user_one = '1' OR chats.user_two = '1'
GROUP BY chats_reply.chat_id
ORDER BY chats_reply.chatReply_id DESC
This query returns everything I'd expect, the problem is it return Message 1 from the chats_reply table when I want it to return Message 2. Any help is greatly appreciated.
Use WHERE for filtering. Not GROUP BY:
SELECT c.chat_id, c.created_at AS ChatTime,
cr.reply, cr.created_at AS ReplyTime, cr.status,
u.name, u.last_name, u.email
FROM chats c INNER JOIN
chats_reply cr
ON c.chat_id = cr.chat_id INNER JOIN
users u
ON (u.user_id = c.user_two AND c.user_one = 1) OR
(u.user_id = c.user_one AND c.user_two = 1)
WHERE 1 IN (c.user_one, c.user_two) AND
cr.chatReply_id = (SELECT MAX(cr2.chatReply_id)
FROM chat_reply cr2
WHERE cr2.chat_id = cr.chat_id
);

MySQL query to return a conversation between 2 users

I'm trying to generate a list of messages in a conversation between 2 users. There are 2 relevant tables:
inbox
id_msg
date_msg
id_user_from
id_user_to
message
user
id_user
name
In this example, I'm user ID 1 (Jon), having a chat with user ID 2 (Anna).
SELECT SQL_CALC_FOUND_ROWS
i.id_msg,
i.id_user_from AS from,
i.id_user_to AS to,
u.name,
i.message,
FROM inbox AS i
INNER JOIN user AS u ON (u.id_user = i.id_user_from OR u.id_user = i.id_user_to)
WHERE (i.id_user_from = 1 AND i.id_user_to = 2) OR (i.id_user_from = 2 AND i.id_user_to = 1)
ORDER BY date_msg DESC
The current problem is that the results are repeated. I'm receiving 2 repeated id_msg values each linked to each user's name, e.g.:
id | id_from | id_to | name | message
1 | 1 | 2 | Jon | Hi Anna!
1 | 1 | 2 | Anna | Hi Anna!
2 | 2 | 1 | Jon | Hello Jon
2 | 2 | 1 | Anna | Hello Jon
I should be receiving this:
id | id_from | id_to | name | message
1 | 1 | 2 | Jon | Hi Anna!
2 | 2 | 1 | Anna | Hello Jon
Any ideas? Thanks!
If you only want the from user to show up, you don't need to match the to user in the join condition;
SELECT SQL_CALC_FOUND_ROWS
i.id_msg, i.id_user_from from_id, i.id_user_to to_id,
u_from.name from_name, u_to.name to_name, i.message
FROM inbox AS i
INNER JOIN user AS u_from ON u_from.id_user = i.id_user_from
INNER JOIN user AS u_to ON u_to.id_user = i.id_user_to
WHERE (i.id_user_from = 1 AND i.id_user_to = 2)
OR (i.id_user_from = 2 AND i.id_user_to = 1)
ORDER BY date_msg DESC
This is because your join is using an or. You really have two names, so they should both be in the query. So, I think this might fix your problem:
SELECT SQL_CALC_FOUND_ROWS i.id_msg, i.id_user_from AS from, i.id_user_to AS to,
ufrom.name as fromname, uto.name as toname, i.message,
FROM inbox i INNER JOIN
user ufrom
ON ufrom.id_user = i.id_user_from
user uto
ON uto.id_user = i.id_user_to
WHERE (i.id_user_from = 1 AND i.id_user_to = 2) OR
(i.id_user_from = 2 AND i.id_user_to = 1)
ORDER BY date_msg DESC;

How to optimize SQL query more?

First at all i am nood into SQL thing, Now i am working on a class project where
I have some tables like
Table user
user_id | username | name
1 | nihan | Nihan Dip
2 | dip | Meaw ghew
more | more | more
Table Friend
you | friend_id
1 | 2
1 | 27
2 | 9
more | more
Table Follow
user_id | follows
1 | 99
7 | 34
Table post
post_id | user_id | type | content | post_time
1 | 1 | text | loren toren | timestamp
2 | 2 | text | ipsum | timestamp
Now i want to get post by users friend and who he follows and offcourse his so i made this SQL
SELECT
username, name,content, post_time
FROM
post
INNER JOIN
user ON user.user_id = post.user_id
WHERE
post.user_id IN (SELECT
friend_id
FROM
friend
WHERE
you = 1
UNION ALL
SELECT
follows
FROM
follow
WHERE
user_id = 1)
OR post.user_id = 1
ORDER BY post_time DESC
LIMIT 10
this query works just fine. I just wanted to know is there anymore optimization could be done? Then how? Please teach me :)
Instead of using IN try it with JOIN add add few more indexes.
SELECT DISTINCT u.name, u.username,
p.content, p.post_time
FROM post p
INNER JOIN user u
ON u.user_id = p.user_id
INNER JOIN
(
SELECT friend_id id
FROM friend
WHERE you = 1
UNION ALL
SELECT follows id
FROM follow
WHERE user_id = 1
) s ON p.user_id = s.ID
ORDER BY post_time DESC
LIMIT 10

Trouble with join statement for selecting data across tables with MYSQL

I'm trying to display events that a user has created and events that he has signed up for. I have three tables for this.
//events
| event_id | event_title | event_details | event_timestamp | userid
1 title1 test 1234 1
2 title2 testing2 123 2
//registration_items : event_id references events.event_id
| id | event_id | task_name
1 2 task 1
//registration_signup : id references registration_items.id
| id | userid | timestamp
1 1 1234
Here's the current query I have. Right now it only displays the event the user created. It should display both created events and ones he signed up for
select events.*, registration_items.*, registration_signup.*, users.username from events
INNER JOIN users on users.userid = events.userid
LEFT JOIN registration_items ON registration_items.event_id = events.event_id
LEFT JOIN registration_signup ON registration_signup.id = registration_items.id
WHERE events.userid = '$user_id' OR registration_signup.userid = '$user_id' ORDER BY events.event_timestamp DESC
For userid1 the output should be
Title
title1 (the user created this)
title2 (the user signed up for this)
For userid2 the output should be
Title
title2
select events.*, registration_items.*, registration_signup.*, users.username
from events
INNER JOIN users on users.userid = events.userid
LEFT JOIN registration_items ON registration_items.event_id = events.event_id
LEFT JOIN registration_signup ON registration_signup.id = registration_items.id
WHERE registration_signup.userid = '$user_id'
union
select events.*, registration_items.*, registration_signup.*, users.username
from events
INNER JOIN users on users.userid = events.userid
INNER JOIN registration_items ON registration_items.event_id = events.event_id
INNER JOIN registration_signup ON registration_signup.id = registration_items.id
WHERE events.userid = '$user_id'
ORDER BY events.event_timestamp DESC
I am not sure if it's correct to guess that you have a typo in the sample data. Because your query works the moment you change the user id to 1 for both events, signed up events.. So please take a look at this reference demo and comment if it's not a typo...
SQLFIDDLE DEMO
query: (your query..)
select u.userid,e.event_id as id,
ri.event_id as evt, e.event_title,
ri.task_name,
rs.timestamp,
u.name from events e
INNER JOIN users u on
u.userid = e.userid
LEFT JOIN registration_items ri ON
ri.event_id = e.event_id
LEFT JOIN registration_signup rs ON
rs.id = ri.id
WHERE e.userid = '1' or
rs.userid = '1'
ORDER BY e.event_timestamp DESC
;
Results:
| USERID | ID | EVT | EVENT_TITLE | TASK_NAME | TIMESTAMP | NAME |
------------------------------------------------------------------
| 1 | 1 | 1 | title1 | task 1 | 1234 | john |
| 1 | 2 | 2 | title2 | task 1.2 | 3456 | john |