How to join more than 2 tables in MySQL? - mysql

I have 3 tables i want to join all tables each other. But my 3rd table not working.
See my table -
users
id | username |is_active
----------|----------------|------------
1 | chinu | 1
2 | sradhanjali | 1
3 | User3 | 0
settings
id | user_id | public_msg_notification
----------|-----------|---------------------------
1 | 1 | 1
2 | 2 | 1
3 | 3 | 1
friends
id | user_id | friend_id | is_block
----------|-----------|---------------------------
1 | 3 | 1 | 0
2 | 1 | 2 | 1
3 | 3 | 2 | 0
Query
SELECT a.username FROM users a
JOIN settings b
JOIN friends c ON(a.id=c.user_id OR a.id=c.friend_id)
WHERE a.username IN('john','piter','rahul','sradhanjali')
AND a.id != '1' AND a.is_active=1
AND a.id=b.user_id AND b.public_msg_notification=1
AND c.is_block=0 GROUP BY a.username
I have run this query in my local only sradhanjali username fetched. But this user is_block=1 in the friends table.
I think My third table friends not working. I want to show that result those usernmes where is_block=0. In above data my output should be zero(0) But I am getting 1 record while execute above query.

We had a chat discussion and I think this question is not meant to be on SO for the most part. I did promise if I could figure it out I would try to provide some insight. At this point I think this is a correct approach, but it is very specific to this instance.
SELECT u.username FROM users u
JOIN (SELECT
IF(u.id=f.user_id, f.friend_id, f.user_id) as ids
FROM users u
JOIN friends f ON (f.user_id=u.id OR f.friend_id=u.id)
WHERE
u.id=$SOME_ID AND f.is_block=0) friends ON (u.id=friends.ids)
JOIN settings s ON (s.user_id=friends.ids)
WHERE s.public_msg_notification=1 AND u.is_active=1
GROUP BY friends.ids
By trying to be too specific you aren't able to open up the query any more and have to do a nested query inside. This should get all users you are friends with THEN see which users are accepting public notifications and are active. I'm fearing this will fail. But this at the least will put you in the right direction.

Related

Writing complex MySQL Join query

This may be simple for some, but I cannot work it out.
I have 3 tables:
Teams, Users, Tags
Teams Users Tags
------------------- ------------------ -----------------------
userID | teamUserID userID | username userID | name | value
------------------- ------------------ -----------------------
1 | 2 1 | dan 2 | myTag | 1
1 | 3 2 | bob 2 | aTag | 2
1 | 4 3 | jon 3 | bTag | 1
4 | rob 4 | cTag | 5
Each team can have a number of users in it, and each user can own a number of tags.
I need a query which will provide a list of users in any given team, with a total number of tags they have.
So when I request results from team 1 (dan's team) it should return this:
-----------------------------------
userID | username | tagTotalValue
-----------------------------------
2 | bob | 3
3 | jon | 1
4 | rob | 5
I have this query so far, but it just gives me one record with an overall total for the whole team, rather than a list of all the users in the team separately with their totals.
SELECT username, SUM(value) tagTotalValue
FROM users u LEFT JOIN tags t
ON u.userID = t.userID
WHERE u.userID IN (SELECT teamUserID FROM teams WHERE userID = 1)
Help!
If anyone can explain a good way of working out how to build these queries, I would be very grateful to learn. Do I just need to do a mySQL course, or is there a simple method I can employ?
I need a query which will provide a list of users in any given team,
with a total number of tags they have.
This seems to have little to do with the query you have written. You should start by joining the three tables together and then aggregating. The query looks something like this:
SELECT t.teamId, u.userId, u.username, count(ta.userId) as numTags
FROM teams t JOIN
users u
ON t.teamUserID = u.UserId LEFT JOIN
tags ta
ON u.userID = ta.userID
WHERE t.teamId = #teamId -- this can be removed
GROUP BY t.teamId, u.userId, u.username;
This query makes the leap that teams has a column that identifies the team -- say teamId.

Mysql finding results not present in jointable

I've got a mysql question that I haven't been able to figure out. Its a little bit different than the other questions I've found here on SO.
I've got three tables
users
____________
ID name
1 John
2 Mike
3 Susie
tasks
___________
ID Name
1 Brush Teeth
2 Shower
3 Check Email
users_tasks
_____________________
ID user_id task_id
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 3 1
Im trying to find out what users haven't completed what tasks yet. I would like the result set to look like this:
user_id task_id
__________________
2 3
3 2
3 3
The closest I have come is this query, which only gives me users that haven't completed at least one of the tasks, but doesn't give me the task.
select * FROM users
right JOIN users_tasks on users.id = users_tasks.user_id
right JOIN tasks on users_tasks.task_id = tasks.id
where tasks.id is null
I cant figure out how to return duplicate users and tasks based on what is missing form the join table.
Thanks in advance
An easy solution is just to require that the entry is not in your completed tasks table:
select * from users, tasks
where not exists (
select * from users_tasks
where users.id = users_tasks.user_id and tasks.id = users_tasks.task_id
);
Result:
+------+-------+------+-------------+
| id | name | id | name |
+------+-------+------+-------------+
| 3 | susie | 2 | Shower |
| 2 | mike | 3 | Check Email |
| 3 | susie | 3 | Check Email |
+------+-------+------+-------------+
One way to do this is to create a set representing the cartesian product of the users and tasks tables. This is what would be the result if every user had done every task. Then do a left join with the actual users_tasks table and filter for null to get the missing items:
select sub.*
from (
select u.id user_id, t.id task_id
from users u, tasks t
) sub
left join users_tasks ut on sub.user_id = ut.user_id and sub.task_id = ut.task_id
where ut.ID is null;

Optimization SQL for getting data from two joined tables (usernames for user-from-id and user-to-id msgs from two tables)

I have table "msgs" with messages between users (their ids):
+--------+-------------+------------+---------+---------+
| msg_id |user_from_id | user_to_id | message | room_id |
+--------+-------------+------------+---------+---------+
| 1 | 1 | 4 |Hello! | 2 |
| 2 | 1 | 5 |Hi there | 1 |
| 3 | 2 | 1 |CU soon | 2 |
| 4 | 3 | 7 |nice... | 1 |
+--------+-------------+------------+---------+---------+
I also have two tables with users names.
Table: user1
+--------+----------+
|user_id |user_name |
+--------+----------+
| 5 | Ann |
| 6 | Sam |
| 7 | Michael |
+--------+----------+
Table: user2
+--------+----------+
|user_id |user_name |
+--------+----------+
| 1 | John |
| 2 | Alice |
| 3 | Tom |
| 4 | Jane |
+--------+----------+
I need to get usernames for two users IDs in every row. Every user-id can be in first or second table with usernames.
I wrote this SQL query:
SELECT DISTINCT
m.msg_id,
m.user_from_id,
CASE WHEN c1.user_name IS NULL THEN c3.user_name ELSE c1.user_name END AS from_name,
m.user_to_id,
CASE WHEN c2.user_name IS NULL THEN c4.user_name ELSE c2.user_name END AS to_name,
m.message
FROM msgs m
LEFT JOIN users1 c1 ON c1.user_id=m.user_from_id
LEFT JOIN users1 c2 ON c2.user_id=m.user_to_id
LEFT JOIN users2 c3 ON c3.user_id=m.user_from_id
LEFT JOIN users2 c4 ON c4.user_id=m.user_to_id
WHERE m.room_id=1
LIMIT 0, 8
It works.
Execute query to get raw data without usernames (without any join) tooks about ~0.1 sec. But it's enough to join only one usernames table (user1 or user2 only) to get this data in about ~6.2 sec. (with join one table). I have quite a lot rows in this tables: 35K rows in msgs, 0.5K in user1, 25K in user2.
Executing query with join two tables (with all this data) is impossible.
How to optimize this query? I just need usernames for user_ids in first "msgs" table.
There are potentially many differences between the queries with and without the joins. I am going to assume that the ids have the appropriate indexes -- primary keys automatically do. If not, then check that.
The obvious solution is to use the original query as a subquery:
SELECT m.msg_id, m.user_from_id,
(CASE WHEN c1.user_name IS NULL THEN c3.user_name ELSE c1.user_name
END) AS from_name,
m.user_to_id,
(CASE WHEN c2.user_name IS NULL THEN c4.user_name ELSE c2.user_name
END) AS to_name,
m.message
FROM (SELECT m.*
FROM msgs m
WHERE m.room_id = 1
LIMIT 0, 8
) m LEFT JOIN
users1 c1
ON c1.user_id = m.user_from_id LEFT JOIN
users1 c2
ON c2.user_id = m.user_to_id LEFT JOIN
users2 c3
ON c3.user_id = m.user_from_id LEFT JOIN
users2 c4
ON c4.user_id = m.user_to_id;
For most data structures, the distinct is also unnecessary.
This also makes (the reasonable assumption) that user_id is unique in the users tables.
Also, use of LIMIT without ORDER BY is highly discouraged. The particular rows you get are indeterminate and might change from one execution to the next.

How to select/match from MySQL table?

I have the following table:
People
---------
ID | Name
---------
1 | John
2 | Sam
And I have another table:
Permissions
-----------
ID | Perm
-----------
1 | View
2 | Edit
3 | Delete
These two tables are linked in a third table:
UserPermissions
----------------------
ID | User | Permission
----------------------
1 | 1 | 1 (View)
2 | 1 | 3 (Delete)
3 | 2 | 1 (View)
I am trying to select a "total" permissions type table, where, if I wanted to get the permission for a user (Lets say user 2 (Sam)), I would get the following table:
UserPermissions
------------------
Permission | User
------------------
1 (View) | 2
2 (Edit) | NULL (Or some other nullish value)
3 (Delete)| NULL
I have only recently started MySQL and I have no idea of what search terms I should be trying to get examples of similar queries. Does anyone know what type of queries I should be searching for / a way to implement this?
If you want to do this for one user, you want a left outer join:
select p.*, up.user;
from Permissions p left outer join
UserPermissions up
on p.Permission = up.Permission and
up.User = 2;
This works for one user.
Sounds like you're just looking for an OUTER JOIN:
SELECT P.Id, P.Perm, UP.Id User
FROM Permissions P
LEFT JOIN UserPermissions UP ON P.Id = UP.Permission

How to select something from one table while checking status from another table?

I have two tables in database:
comments table users table
| u_id | text | | u_id | premium |
| 9 | .. | | 9 | 1 |
| 10 | .. | | 10 | 0 |
| 9 | .. |
I want to select text from comments table for user in case only when this user has premium status (1). But if I want to check status of this user I need do another mysql query. Is this possible to do check that in one query?
$premium=sql_select("SELECT premium FROM users WHERE u_id LIKE '".$_GET['u_id']."'");
if ($premium[1][0]=1) {
$text=mysql_query("SELECT text FROM comments WHERE u_id LIKE '".$_GET['u_id']."'");
}
else //this user has no premium account so text will not be selected.
The following query joins the tables and gets all users with premium 1.
SELECT c.u_id, c.text FROM comments_table as c
LEFT JOIN ON users_table as u ON u.u_id = c.u_id
WHERE u.premium = 1
Use an (inner) join:
SELECT text
FROM comments_table c
JOIN users_table u ON u.u_id = c.u_id AND u.premium = 1
WHERE c.u_id = ?