I am writing a simple chat service. I want to pick out a messages thread between two people only a sender and a recipient using either their usernames or user ids. I have my query below. It has a slight problem, is returning a message twice. How can I fix this?
For example if my sender has the uid '101' and my recipient has the username 'janed', my query is
SELECT * FROM chat LEFT JOIN users ON sender=uid OR receiver=uid WHERE username='janed' OR (sender='101' AND receiver='janed') OR (sender='janed' AND receiver='101') ORDER BY msg_id ASC
Users table
---------------------------------
uid |fname |mname |username |
---------------------------------
101 |John |Doe |jdoe |
---------------------------------
102 |Jane |Doe |janed |
---------------------------------
103 |Ann |Other |aother |
---------------------------------
Chat table
---------------------------------------------
msg_id |sender |receiver |content |
---------------------------------------------
1 |101 |102 | Hello Jane |
---------------------------------------------
2 |102 |101 | Hello John |
---------------------------------------------
3 |103 |101 | Hi John |
---------------------------------------------
Add a GROUP BY clause
SELECT
*
FROM
chat
LEFT JOIN
users ON sender = uid OR receiver = uid
WHERE
username = 'janed'
OR (sender = '101' AND receiver = 'janed')
OR (sender = 'janed' AND receiver = '101')
GROUP BY msg_id
ORDER BY msg_id ASC
SELECT
u.*, c.*
FROM Users u
LEFT JOIN Chat c ON (
c.sender = u.uid OR c.receiver = u.uid
)
WHERE u.uid = 101 OR u.uid = 102 /* and/or other conditions */
GROUP BY c.msg_id
ORDER BY c.msg_id ASC
Related
Suppose I have a table named users consist of columns: user_id, user_name, user_created_by.
+------------------+----------------------+-------------------+
| user_id + user_name + user_created_by +
+------------------+----------------------+-------------------+
| 1 | John | 1 |
| 2 | Ann | 1 |
| 3 | Paul | 2 |
| 4 | King | 2 |
| 5 | Dirk | 3 |
+------------------+----------------------+-------------------+
The value of user_created_by is the user_id who created that record. Now, I want to make a query that results one specific row with added column let's say user_created_by_name which is the user_name of the user_id from the user_created_by. Suppose we want to get "Paul"'s record with who (the name) create it (temporary new column). For ease of understanding this is my expected result:
+----------+--------------+-------------------+------------------------+
| user_id | user_name | user_created_by | user_created_by_name |
+----------+--------------+-------------------+------------------------+
| 3 | Paul | 2 | Ann |
+----------+--------------+-------------------+------------------------+
this is my query using codeigniter:
$query=$this->db->query("SELECT *,
(SELECT user_name FROM users WHERE user_id = user_created_by)
AS "user_created_by_name" FROM users WHERE user_id=3);
But my result are:
+----------+--------------+-------------------+------------------------+
| user_id | user_name | user_created_by | user_created_by_name |
+----------+--------------+-------------------+------------------------+
| 3 | Paul | 2 | NULL |
+----------+--------------+-------------------+------------------------+
You culd use a self join (join the same table two time) using alias for fere to the tables as different sets of data
SELECT a.user_id, a.user_name, a.user_created_by, b.user_name as user_created_by_name
from users a
inner join user b on a.user_created_by = b.user_id
where a.user_id = 3
use self join
select u1.user_id, u1.name as user_name,
u2.user_created_by
,u2.user_name as createdby from users u1
join users u2 on u1.user_id=u2.user_created_by
where u1.user_id=3
You can solve this problem using a JOIN.
$sql = "SELECT users.user_id, users.user_name, user_created_by_name.user_name,
FROM users JOIN users AS user_created_by_name ON users.user_id = user_created_by_name.user_id WHERE users.user_id = 3";
$query=$this->db->query($sql);
If you you have users that were not created by another user use a LEFT JOIN instead:
$sql = "SELECT users.user_id, users.user_name, user_created_by_name.user_name,
FROM users LEFT JOIN users AS user_created_by_name ON users.user_id = users.user_id WHERE user_created_by_name.user_id = 3";
$query=$this->db->query($sql);
This will work:
SELECT a.user_id as User_id,
a.user_name as Name,
b.user_id as Created_by_user_id,
b.user_name as Created_by_name
FROM users AS a
INNER JOIN users AS b
ON a.user_id = b.user_created_by
WHERE a.user_id = 3
It is called a self-join, which is used when combining two records of the same table.
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;
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
I have two table:
Users Mail
------- ------
ID | Username ID | UserID | SenderID | Something
--------------- ---------------------------------------------------
1 | A 1 | 2 | 1 | Becoming Mad with SQL
2 | B 2 | 3 | 4 | Mee too
I am trying this:
SELECT *
a.userid, a.senderid, a.something,
b.username
FROM
mail a
LEFT JOIN users b on b.id=a.senderid
WHERE
a.id='1'
Output is/similar:
a.Userid | a.senderid | a.something | b.username
--------------------------------------------------
2 | 1 | becoming.. | A
My Expected output is like this (username B and A in one row):
Userid | senderid | something | username | Username of UserID
---------------------------------------------------------------
2 | 1 | becoming..| A | B
How can i get UserID and its Username in the same query? Because i already have left join users b on b.id=a.senderid
SELECT a.userid,
a.senderid,
a.something,
b.username,
c.username
FROM mail a
LEFT JOIN users b ON b.id = a.senderid
JOIN users c ON c.id = a.UserID
WHERE a.id='1'
Use two copies of the users table, one for the sender, one for the user.
SELECT a.userid,
a.senderid,
a.something,
b.username,
c.username
FROM mail a,
users b,
users c
WHERE a.id='1'
AND b.id=a.senderid
AND c.id=a.Userid
Make sure you put indexes in your tables too for mail's id column and users senderid and user id columns - they'll help speed things up.
I have 3 tables: user, 'user_friends' and 'blog_post'
The schema is similar to the following:
user
id | username
-------------------
1 | jim
-------------------
2 | mary
-------------------
3 | george
-------------------
4 | julie
user_friends
user_id | friend_id
----------------------
1 | 2
----------------------
2 | 3
----------------------
2 | 4
blog_posts
id | title | user_id
------------------------------
1 | test_1 | 1
------------------------------
2 | test_2 | 2
------------------------------
3 | test_3 | 3
------------------------------
4 | test_4 | 4
Ok, so you can see each user has made a blog post. Users have 'friends'. What I'm looking to do, is display each users friends blog posts.
So, If I'd like to see Jims friends posts, it should show mary's post of test_2. If I want to see mary's friends posts, it should show george and julie's posts of test_3 and test_4
Is there an easy way of doing this? Could I use sub-selects?
Many thanks
Yes you can use a sub-selection.
Something like this should work :
SELECT * FROM blog_posts WHERE user_id in
(SELECT friend_id FROM user_friend WHERE user_id=1)
Could be as simple as that (variant with a JOIN):
SELECT bp.*
FROM user_friends uf
JOIN blob_posts bp ON bp.user_id = uf.friend_id
WHERE uf.user_id = my_id
Select *
From blog_posts
Where user_id in
(Select friend_id
From user_friends
where user_id = 1);
the number at the end can be whatever user ID you are looking for.
You can use IN
SELECT * FROM blog_posts WHERE user_id IN (
SELECT friend_id FROM user_friends WHERE user_id = X)
SELECT bp.*
FROM blog_posts bp
INNER JOIN user_friends uf ON bp.user_id = uf.friend_id
INNER JOIN user u ON u.id = uf.user_id
WHERE u.username = "jim"
Try this request:
SELECT bp.title
FROM blog_posts bp
JOIN user_friends uf ON (bp.user_id = uf.friend_id)
WHERE uf.user_id = 1;