Is there a way I can simplify this MySQL query? - mysql

The point here is to get a child user from the users table that is not already assigned to a particular organization. However, still include it if the child user is assigned to the current user.
It works, but I feel like the syntax could be simpler somehow:
SELECT u.userId, u.firstName, u.lastName, u.username, u2.services_user_id
FROM user u
LEFT JOIN user u2 ON u.userId = u2.services_user_id
WHERE u.enabled = 1
AND u.organization_id = 1
AND u.userId NOT IN (
SELECT services_user_id FROM user
WHERE organization_id = 2
AND services_user_id <> 19
AND services_user_id IS NOT NULL
)

I guess you could simplify your query as follows by moving your filter criteria in on clause
SELECT u.userId, u.firstName, u.lastName, u.username, u2.services_user_id
FROM user u
LEFT JOIN user u2 ON u.userId = u2.services_user_id
AND (u2.organization_id <> 2 OR u2.services_user_id = 19)
WHERE u.enabled = 1
AND u.organization_id = 1
A sample data set would be helpful to verify the results of both queries

I reworked my query to use NOT EXISTS and the SELECT 1 FROM user instead. Both of these are much faster and more efficient for my purposes.
SELECT u.userId, u.firstName, u.lastName, u.username
FROM user u
LEFT JOIN user u2 ON u.userId = u2.services_user_id
WHERE u.enabled = 1
AND u.organization_id = 14
AND NOT EXISTS (
SELECT 1 FROM user u3
WHERE
u3.organization_id = 1
AND u3.services_user_id <> 19
AND u3.services_user_id IS NOT NULL
AND u.userId = u3.services_user_id
)
Same result, but cleaner and only pulling out what I needed.

Related

SQL query to find all users, User 'A' follows and then check if another User 'B' also follows the same users

I want to display all users data, who User 'A' is following. And then further check if User 'B' is also following some users of User 'A'.
I managed to get al users data, who User 'A' is following. But don't understand how to query for the second condition.
Here is my Fiddle link with an example: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=29a7d1e29f794a8f18a89fe45c06eaa9
You can try to let your User 'B' in a subquery then do OUTER JOIN
SELECT u.*,
IF(friend_id IS NULL,0,1) amIfollowing
FROM users u
LEFT JOIN (
Select friend_id
from friends
where user_id = 5
) f ON f.friend_id = u.id
WHERE u.id IN (SELECT f.friend_id
FROM friends f
WHERE f.user_id = 1)
ORDER BY u.id
sqlfiddle
If I understand correctly you can try to use only one subquery for friends and then use the condition aggregate function to get the result.
SELECT u.id,
u.image_width,
MAX(CASE WHEN f.user_id = 5 THEN 1 ELSE 0 END) amIfollowing
FROM users u
JOIN (
Select friend_id,user_id
from friends
where user_id IN (1,5)
) f ON f.friend_id = u.id
GROUP BY u.id,
u.image_width
ORDER BY u.id
You could use exists here to check if the corresponding IDs exist:
SELECT *,
case when exists (
select * from friends f
where f.friend_id = u.id and f.user_id = 5
) then 1 else 0 end amIfollowing
FROM users u
WHERE u.id IN (SELECT f.friend_id
FROM friends f
WHERE f.user_id = 1);
Example Fiddle
Looks like a JOIN will do, with distinct
SELECT distinct u.*, (f2.user_Id is not null) amIfollowing
FROM users u
JOIN friends f ON u.id = f.friend_id
LEFT JOIN friends f2 on f2.friend_id = f.friend_id and f2.user_id = 5
WHERE f.user_id = 1
ORDER BY u.id

how to get not matched record in SQL

i have a tables like below
tableName: users
tableName: projects
tableName: user_project
So i want to get users who are not a part of project "1".
i tried like this but no luck
SELECT u.id, u.username
FROM testdb.user_project up
LEFT JOIN testdb.users u
ON up.userId = u.id
WHERE up.projectId=1 AND u.id IS NULL
My expected output
id | username
--------------
3 | u3
4 | u4
can you please help me out of this
Thank you in advance
The below query should work
select u.*
from users u
where u.id not in (select userId from user_project where projectId = 1)
use not exists
select u.* from users u
where not exists ( select 1 from user_project up
where up.userid= u.id and up.projectid=1)
Basically you want the users that are not associated with Project 1 in the relation table. You can do that using "where not exists".
The solution is better, cause exists removes the need to take care of duplicate values, cause one single occurrence is enough to match (or not match) the definition.
select
u.id
, u.username
from users u
where not exists (
select
1
from user_project up
where 1=1
and up.projectID = 1
and up.userId = u.id
)
SELECT u.id, u.username
FROM testdb.user_project up
LEFT JOIN testdb.users u
ON up.userId = u.id
WHERE up.projectId <> 1;

How to write mysql query to achieve the following type of join (Join based on value of a column )

Table users:
id----email
1-----s#s.com
2-----p#p.com
Table user_buddies
id-----user_id----buddy_id----status enum('accepted','pending')
1------1----------2-----------pending
Suppose I am querying with respect to user 2 then I want to get user 2 email. If I am querying with respect to user 1 then I want to get user 1 email.
The below query is always returning empty rows.
SELECT
users.email,
ub1.*, ub2.*
FROM
users
JOIN user_buddies ub1 ON users.id = ub1.user_id
JOIN user_buddies ub2 ON users.id = ub2.buddy_id
WHERE
users.id = 1;
Can anyone please help me in this?
Thank you.
Expected result:
email-----user_id-----buddy_id-----status
s#s.com --1-----------2------------pending (If queryed on user 2)
p#p.com---1-----------2------------pending (If queried on user 1)
Context:
When user1 sends request to user2 only one row is added to the user_buddies table with status=pending. So, both for user1 and user2 buddy list is created using same row. So if queried against user2 email needed is user2's.
You may check the following query:
SELECT
users.email,
ub1.user_id,
ub1.buddy_id,
ub1.`status`
FROM
users
JOIN user_buddies ub1 ON users.id = ub1.user_id OR users.id = ub1.buddy_id
WHERE users.id = 2;
SQL FIDDLE DEMO
Result:
email user_id buddy_id status
p#p.com 1 2 pending (if queried on users.id = 2)
s#s.com 1 2 pending (if queried on users.id = 1)
EDIT:
SELECT
(
SELECT
u.email
FROM users u
WHERE u.id =
IF (
users.id = ub1.user_id,
ub1.buddy_id,
ub1.user_id
)
) AS buddyEmail,
ub1.user_id,
ub1.buddy_id,
ub1.`status`
FROM
users
INNER JOIN user_buddies ub1 ON users.id = ub1.user_id
OR users.id = ub1.buddy_id
WHERE users.id = 2;
Check this fiddle of this new query
SELECT 'Userid' querysource, u.id, u.email, ub.*, u1.EMAIL AS Buddyemail
FROM #users u
JOIN #user_buddies ub ON u.id = ub.user_id
JOIN #users u1 ON u1.id = ub.BUDDY_ID
WHERE u.id = 1
UNION
SELECT 'Buddyidid', u.id, u.email, ub.*, u1.email AS Buddyemail
FROM #users u
JOIN #user_buddies ub ON u.id = ub.buddy_id
JOIN #users u1 ON u1.id = ub.user_ID
WHERE u.id = 1

Join query returning empty as well

I have three tables (many more cols but listed important ones):
users
user_id - name
1 DAN
2 TED
3 SAM
list_shares
list_shares_id - user_id - list_id
1 1 123
2 3 123
3 2 456
list_contribute
list_contr_id - list_id - can_contribute
1 123 3
I want to show all users who are in table list_shares under a list_id, join that with users table to get user info, and also count how many of them are also in the contribute table
Basically - a user can share a list with users and also invite some of the users to contribute, but not all those sharing are allowed to contribute, hence the separate list_contribute table.
here's what I'm using firstly which just shows all users with a certain ID:
select u.name, u.live_prof_pic, u.url, u.user_id from list_shares ls
join users u on ls.user_id = u.user_id
where ls.list_id = '123'
This brings up two results, which is correct - the next query is trying to find which of these two are in the list_contribute table also - but, it reduces the result to one whereas i want it to return both and show 0 for how_many if not in list_contribute
select u.name, u.live_prof_pic, u.url, count(ls.list_shares_id) as how_many, u.user_id from list_shares ls
join users u on ls.user_id = u.user_id
left join list_contribute lc on ls.list_id = lc.list_id
where ls.list_id = '123'
In the above data i want to return
user_id name how_many
3 SAM 1
1 DAN 0
Add a GROUP BY to make it a standard SQL aggregate
select u.name, u.live_prof_pic, u.url, count(ls.list_shares_id) as how_many, u.user_id
from
list_shares ls
join users u on ls.user_id = u.user_id
left join list_contribute lc on ls.event_id = lc.event_id
where ls.list_id = '123'
group by u.name, u.live_prof_pic, u.url, u.user_id
MySQL has a rubbish extension that tries to remove the requirement but gives incorrect data often
Edit, after comment.
You should still use correct GROUP BY syntax
However, your COUNT should be COUNT(lc.event_id) to count child rows.
Use query below if it does not return desired result set, it means you have orphaned record sets in list_shares which does not have corresponding users.
select
u.name
, u.user_id
, count(lc.list_id) as how_many
from
list_shares ls
INNER JOIN
users u
on
ls.user_id = u.user_id
left join
list_contribute lc
on
ls.list_id = lc.list_id
where
ls.list_id = '123'
GROUP BY
u.name
, u.user_id
Not sure how mysql count works so to be 100% sure:
select
u.name
, u.user_id
, SUM(CASE WHEN lc.list_id IS NOT NULL THEN 1 ELSE 0 END CASE) as how_many
from
list_shares ls
INNER JOIN
users u
on
ls.user_id = u.user_id
left join
list_contribute lc
on
ls.list_id = lc.list_id
where
ls.list_id = '123'
GROUP BY
u.name
, u.user_id
If I got you right - here's what you need
SQL Fiddle Example
select
u.user_id, u.name,
count(case when lc.can_contribute = u.user_id then 1 else null end) as HowMany
from users as u
inner join list_shares as ls on ls.user_id = u.user_id
inner join list_contribute as lc on lc.list_id = ls.list_id
group by
u.user_id, u.name

Select the users are not friend of a specific user

Hi, I have these two tables: users and friends (friend_status = 1 means the request is sent, friend_status = 2 means they are friends). Now I want to select all users are not friend of a specific user. How to do?
Assuming the current user is 1. I tried this SQL. It works but it's too long and slow. The first selects all users sent request to user1 but not accepted. The second selects all users receive request from user1. The third and the fourth selects all users is not in "friends" table.
SELECT user_id, name, email
FROM
(
SELECT user_id, name, email
FROM users u INNER JOIN friends f ON u.user_id = f.sender
WHERE f.receiver = 1 AND friend_status <> 2
UNION
SELECT user_id, name, email
FROM users u INNER JOIN friends f ON u.user_id = f.receiver
WHERE f.sender = 1 AND friend_status <> 2
UNION
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.sender
WHERE f.receiver IS NULL
GROUP BY user_id
UNION
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.receiver
WHERE f.sender IS NULL
GROUP BY user_id
) T
GROUP BY user_id
Update: Add a pic.
SELECT
a.user_id,
a.name,
a.email,
b.status IS NOT NULL AS friend_status
FROM
users a
LEFT JOIN
friends b ON
a.user_id IN (b.sender, b.receiver) AND
1 IN (b.sender, b.receiver)
WHERE
(b.friend_id IS NULL OR b.status <> 2) AND
a.user_id <> 1
You had asked a question previously here - "Select users who aren't friends with anyone", and I provided an answer which utilized a LEFT JOIN.
Building off of that, to select users who aren't friends with a specific user, we just simply need to add that specific user's ID to the LEFT JOIN condition (1 IN (b.sender, b.receiver).
Minor Edit: Unless the user can friend him/herself, it wouldn't make sense to also select the user who we're selecting against!! So I added WHERE a.user_id <> 1.
Assuming you want to perform the query on user_id 1:
SELECT user_id, name, email
FROM users AS u
WHERE NOT EXISTS (SELECT * FROM friends AS f
WHERE (f.sender = u.user_id AND f.receiver = 1 AND f.friend_status = 2)
OR (f.sender = 1 AND f.receiver = u.user_id AND f.friend_status = 2)
)
AND u.user_id <> 1
The subquery fetches all the established friendship relationship in which user 1 is either the sender or the receiver. The outer query selects all users for which no such relationship exists. The user with ID 1 is excluded from the query using the last line, as, even if he cannot be friend with himself, I suppose that he should not appear in the final query result.
You may be able to simplify this by using something like this:
SELECT user_id, name, email
FROM
(
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.sender
WHERE IFNULL(friend_status,0) <> 2
GROUP BY user_id
UNION
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.receiver
WHERE IFNULL(friend_status,0) <> 2
GROUP BY user_id
) T
GROUP BY user_id
The IFNULL function returns the value of the first parameter, replacing NULLs with the value of the value second parameter. In this case it means that friend_status will be treated as 0 if there is no matching friend in the friends table, which allows you to reduce the number of selects in the UNION by half.
Try this query
select
u.user_id,
u.name,
u.email,
ifnull(f.friend_status,0) as Relation
from users as u
left join friends as f
on f.sender = u.user_id
where u.user_id not in(select
sender
from friends
where sender = 1)
Here sender = 1 means the user id = 1. You can pass user id to restrict this condition. Also status 0 means he is not friend. and 1 , 2 , 3 are according to your rules