SQL joins and Subqueries , Subquery to SQL joins - mysql

I wrote this SQL query to get friends of user who is not in the invitation table , and it works will , however i read that subqueries are performance eaters and I am not very good with JOINS, any help for modifying this query to be just in joins will be really appreciated.
Here is the SQL Query
SELECT friend.id,
friend.first_name
FROM friends AS friend
INNER JOIN friends_users AS friendsUser
ON ( friend.id = friendsUser.friend_id
AND friend.id NOT IN (SELECT friend_id
FROM friends_invitations
WHERE friends_invitations.user_id = 1) )
ORDER BY friendsUser.id ASC
Here is the tables structure
friends
id   first_name
friends_users
id  friend_id  user_id
friends_invitations
id  friend_id user_id
Any help will be really appreciated

A subquery is not necessarily a performance eater, is your query presenting performance issues?. Anyway, most times the fastest way to do your query would be using a NOT EXISTS:
SELECT friend.id,
friend.first_name
FROM friends AS friend
INNER JOIN friends_users AS friendsUser
ON friend.id = friendsUser.friend_id
WHERE NOT EXISTS (SELECT 1 FROM friends_invitations
WHERE friends_invitations.user_id = 1
AND friend_id = friend.id)
ORDER BY friendsUser.id ASC
Here is a link explaining the differences between NOT IN, LEFT JOIN and NOT EXISTS (for SQL Server). So, test this different options and choose the right one for your tables.

you can use LEFT JOIN for this,
SELECT friend.id,
friend.first_name
FROM friends AS friend
INNER JOIN friends_users AS friendsUser
ON friend.id = friendsUser.friend_id
LEFT JOIN friends_invitations
ON friend.id = friends_invitations.friend_id AND
friends_invitations.user_id = 1
WHERE friends_invitations.friend_id IS NULL
ORDER BY friendsUser.id ASC

Related

Easy SQL Query - Aligning foreign keys

I'm taking longer than I expected with an easy Query in MySQL. I think it's gonna be a nested query but I don't see it easily.
I have 3 tables: Users, Comments, and Businesses. Comments have business_id, and user_id as foreign keys.
So I want the result of users.name and comments.review, having the number of the business.
So my First (and wrong) attempt was:
SELECT users.name, users.image, comments.review
FROM reviews JOIN users JOIN businesses
WHERE reviews.user_id=users.id AND reviews.business_id=4;
I want to set that PrimaryKey.user_id is equal to ForeignKey.users.id.
From all of the comments, I want to take these which are from the business_id=4.
It gives me failiure with both 'WHERE' clauses. So not sure if I could fix this with a nested query or maybe with a JOIN clause?
Any help will be appreciated!
Thank you all. [Edited Query]
Try this out and let me know in case of any queries.
select c.name,c.image,a.review
from
comments a
inner join
(select * from buisnesses where buisness_id = 4) b
on a.buisness_id = b.buisness_id
inner join
users c
on a.user_id = c.user_id;
or
select b.name,b.image,a.review
from
comments a
inner join
users b
on a.user_id = b.user_id
where a.buisness_id = 4;
Give this a try:
SELECT
users.name,
users.image,
comments.review
FROM reviews
JOIN users
ON reviews.user_id = users.id
JOIN businesses
ON reviews.business_id = business.business_id
WHERE reviews.business_id=4;
Since you're not using any of the columns from the business table, you could probably drop it from the query:
SELECT
users.name,
users.image,
comments.review
FROM reviews
JOIN users
ON reviews.user_id = users.id
WHERE reviews.business_id=4;

How can i do better query in mysql

I want to search a user that is not in specific group.
I have a working query in MYSQL and i need some advice and some help.
Here is my query.
SELECT id, fullname FROM users WHERE
id NOT IN (
SELECT user_id FROM group_members WHERE group_id = $groupId
)
AND fullname LIKE $serchKey
the subquery is getting all id on a group then use it as reference in WHERE clause (id NOT IN) of main query, I have no large data by now. i think if i have large data and getting all id as reference use in (id NOT IN) i think it will took large time before getting the result. what can you say?
can you give me a good suggestions for this. thanks
What you have done is the best way as I can think of with relate to the condition and code maintainability.
SELECT id, fullname
FROM users
WHERE id NOT IN (SELECT user_id FROM group_members WHERE group_id = $groupId)
AND fullname LIKE $serchKey
But there is an alternative using LEFT JOIN which is arguable on the performance. (I didnt check this SQL, please check it in your DB)
SELECT distinct u.id
FROM users u
LEFT JOIN group_members gm
ON u.id = gm.user_id
WHERE gm.user_id IS NULL
AND u.fullname like $serchkey

SQL query, which one is more sufficient?

I have a database with three tables:
post
user_id
friendship
user_id
friend_id
status
I want to select all posts whose author (user_id) is current_user's friend
I am wondering which one of the following statement is more efficient? (1 is current user's id, 2 is the code for being friend)
1)
SELECT * FROM posts
INNER JOIN friendships AS fs
ON fs.user_id=1 AND fs.friend_id=posts.user_id AND fs.status=2;
2) query twice
SELECT id FROM friendships
WHERE user_id = 1 AND status = 2
# Assuming get (1,2,3)
SELECT * FROM posts WHERE user_id IN (1,2,3)
Can anyone tell me which is faster? Because I do not have enough data, I can not test....
Neither. Join your tables in the same order you would access them as a human:
SELECT p.*
FROM friendships f
JOIN posts p ON p.user_id = f.friend_id
WHERE f.user_id = 1
AND f.status = 2
Here an index will be used based on the WHERE clause to find rows in friendships, which will then be used to access posts via an index.
Make sure there are indexes on posts.user_id and friendships.user_id.

mySQL slow counting primary keys with subquery

The following query is taking 5.5 seconds. Since this is a simple primary key count and both tables have <5000 records, I'm quite surprised at how slow it is. Is there any workaround to increase performance?
SELECT COUNT(*)
FROM users
WHERE (SELECT COUNT(*)
FROM clients
WHERE userID=users.id)=0
I'm counting the number of users who have no clients.
Try this query
SELECT
COUNT(*)
FROM
users
WHERE NOT EXISTS
(SELECT
userID
FROM
clients
WHERE
userID=users.id)
Alternatively you can try this
SELECT
count(*)
FROM
users u
LEFT JOIN
clients c
ON
u.id = c.userId
WHERE
c.userId IS null
Create index on id columns
Hope this helps
Try this:
SELECT COUNT(*) FROM users u
left join clients c
on u.id = c.userID
where u.id not in (select userID from clients)
DEMO HERE

MySQL query optimization: Multiple SELECT IN to LEFT JOIN

I usually go with the join approach but in this case I am a bit confused. I am not even sure that it is possible at all. I wonder if the following query can be converted to a left join query instead of the multiple select in used:
select
users.id, users.first_name, users.last_name, users.description, users.email
from users
where id in (
select assigned.id_user from assigned where id_project in (
select assigned.id_project from assigned where id_user = 1
)
)
or id in (
select projects.id_user from projects where projects.id in (
select assigned.id_project from assigned where id_user = 1
)
)
This query returns the correct result set. However, I guess the repetition of the query that selects assigned.id_project is a waste.
You could start with the project assignments of user 1 a1. Then find all assignments of other people to those projects a2, and the user in the project table p. The users you are looking for are then in either a2 or p. I added distinct to remove users who can be reached in both ways.
select distinct u.*
from assigned a1
left join
assigned a2
on a1.id_project = a2.id_project
left join
project p
on a1.id_project = p.id
join user u
on u.id = a2.id_user
or u.id = p.id_user
where a1.id_user = 1
Since both subqueries have a condition where assigned.id_user = 1, I start with that query. Let's call that assignment(s) the 'leading assignment'.
Then join the rest, using left joins for the 'optional' tables.
Use an inner join on user that matches either users of assignments linked to the leading assignment or users of projects linked to the leading project.
I use distinct, because I assumen you'd want each user once, event if they have an assignment and a project (or multiple projects).
select distinct
u.id, u.first_name, u.last_name, u.description, u.email
from
assigned a
left join assigned ap on ap.id_project = a.id_project
left join projects p on p.id = a.id_project
inner join users u on u.id = ap.id_user or u.id = p.id_user
where
a.id_user = 1
Here's an alternative way to get rid of the repetition:
SELECT
users.id,
users.first_name,
users.last_name,
users.description,
users.email
FROM users
WHERE id IN (
SELECT up.id_user
FROM (
SELECT id_user, id_project FROM assigned
UNION ALL
SELECT id_user, id FROM projects
) up
INNER JOIN assigned a
ON a.id_project = up.id_project
WHERE a.id_user = 1
)
;
That is, the assigned table's pairs of id_user, id_project are UNIONed with those of projects. The resulting set is then joined with the user_id = 1 projects to obtain the list of all users who share the projects with the ID 1 user. And now it only remains to retrieve the details for those users, which in this case is done in the same way as in your query, i.e. using an IN clause.
I'm sorry to say that I don't have MySQL to thoroughly test the performance of this query and so cannot be quite sure if it is in any way better or worse than your original query or than the one suggested both by #GolezTrol and by #Andomar. Generally I tend to agree with #GolezTrol's comment that a query with simple (semi- or whatever-) joins and repetitive parts might turn out more efficient than an equivalent sophisticated query that doesn't have repetitions. In the end, however, it is testing that must reveal the final answer for you.