How to use Where before Left Join MySQL - mysql

I have two tables that have a structure like this. First the users table:
id | email | password
1 'email' 'pass'
2 'new2' 'pass'
and the report table:
user_id | field | text
1 4 Tom
How can I return back the the email and password values even if the user doesn't have a match in the report table? This is what I have so far.
select a.email, a.password, b.text from users a
left join data b
on a.id = b.user_id
and b.field = 4
and a.id = 2;
Desired output to get info on user with ID of 2:
email | password | text
'new2' 'pass'
I currently don't get anything back with what i've tried so far

Conditions on the first table in a left join go in the where clause. Conditions on the second table go in the on clause:
select u.email, u.password, d.text
from users u left join
data d
on u.id = d.user_id and d.field = 4
where a.id = 2;
The rule might seem arbitrary at first. However, it is not. The left join returns all rows in the first table regardless of whether the on clause evaluates to true. Hence, a filtering condition on the first table does not filter out any rows. The where clause does this filtering.

Try this:
SELECT
u.email
, u.password
, r.text
FROM
users AS u
LEFT JOIN report AS r
ON r.user_id = u.id
WHERE
u.id = 2

I'm not sure you pasted your query into your question correctly, but if I understand what you're after, this should work:
SELECT a.email, a.password, b.text
FROM users a
LEFT JOIN report b ON a.id = b.user_id
WHERE a.id = 2
It isn't clear why you are trying to check for b.field, but if you need to do so, then go ahead an add it to the LEFT JOIN. In general, put conditions in the LEFT JOIN ... ON when you still want rows to be returned, and put conditions in the WHERE clause when they rows should not be returned if the condition isn't met.

Related

SQL - Joining 2 tables, show all from tbl1 and data from tbl2 depending on condition

Im trying to show a full list of all users in my DB aswell as extra information from a second table depending on whether they have a record in the second table
Im using MySQL, ive tried a few left join/right join union combos but nothing i have works
SELECT users.id, users.name, success.URL_ID, success.docreqid FROM users
LEFT JOIN success ON users.id = success.userid
where docreqid IS NULL
union
SELECT users.id, users.name, success.URL_ID, success.docreqid FROM users
RIGHT JOIN success ON users.id = success.userid
where docreqid = 1;
I have a small table of 10 users. Only one user in my db has a record in the success tbl against docreqid '1'.
I want a table of ALL users and the URL_ID for their form if they have submitted it.
The above code works perfectly for this.
If i change the last line to:
where docreqid = 2;
I only get 9 results (the user with a record for docreqid '1' is missing).
I would like this table to show all 10 users and 'NULL' in the URL_ID & docreqid columns until they have completed the required action.
A left join should do what you want:
SELECT u.id, u.name, s.URL_ID, s.docreqid
FROM users u LEFT JOIN
success s
ON u.id = s.userid AND s.docreqid = 1;
The LEFT JOIN returns all rows in the first table -- no WHERE is filtering results. The ON only matches rows in success that meet the additional condition in the ON clause.

Return a set of SQL Results based on criteria from other tables

I wasn't sure how to actually title this question, but if you got in here, I'll try to explain it to the best of my ability.
You can find my SQL Fiddle here.
SELECT *
FROM `challenges`
LEFT JOIN `challenges_competitors` ON `challenges_competitors`.`challenge_id` = `challenges`.`id`
LEFT JOIN `users` ON `users`.`id` = `challenges_competitors`.`user_id`
WHERE `challenges`.`owner_id` != 3 AND `challenges`.`status` = 'pending'
ORDER BY `challenges`.`id`;
Basically what I want to do with the query is return any challenge that user3 does not own or is part of.
There are two tables involved for this. The first table is challenges. This table holds the user id as owner_id, as well as the challenge id and some other data. Then there's the challenges_competitors table that holds challenge_id and user_id to connect that table with both challenges and the users.
When I run the query and join the tables, there are bound to have duplicates because a challenge can have many competitors. So what I want to do is if there is a challenge that the user3 does not own, but he is part of this challenge, to not get that row back.
I really hope I explained this well. lol
To get the most basic information about which challenges (their id) aren't being owned by users.id = 3 and that don't have that user as a competitor altering your query by adding NOT EXISTS clause would be sufficient.
SELECT c.id
FROM `challenges` AS c
WHERE
c.`owner_id` <> 3 -- discard challenges that have user 3 as their owner
AND c.`status` = 'pending'
AND NOT EXISTS ( -- discard challenges that have user 3 as their competitor
SELECT 1
FROM `challenges_competitors` AS cc
WHERE
cc.`user_id` = 3 -- limit this query to return only rows where user 3 is a competitor
AND cc.`challenge_id` = c.`id` -- join condition with challenges table
);
Here's your modified SQL FIDDLE.
To get the entire set of columns that you have attached in your query you could keep the joins, as #xQbert suggested in his comment.
SELECT *
FROM `challenges` c
LEFT JOIN `challenges_competitors` cc
ON cc.`challenge_id` = c.`id`
LEFT JOIN `users` u ON u.`id` = cc.`user_id`
WHERE
c.`owner_id` != 3
AND c.`status` = 'pending'
AND NOT EXISTS (
SELECT 1
FROM `challenges_competitors` cc2
WHERE cc.`id` = cc2.`id` and cc2.`user_id` = 3
)
ORDER BY c.`id`;
Because owner is also a row in the user table you need to include the user table as an alias. I'm not quite sure what you need to get back - I don't understand exactly what the question is, but you should be able to add a where clause to this to get what you want.
SELECT *
FROM `challenges`
JOIN `challenges_competitors` ON `challenges_competitors`.`challenge_id` = `challenges`.`id`
JOIN `users` ON `users`.`id` = `challenges_competitors`.`user_id`
JOIN `users` AS `owners` ON `owners`.`id` = `challenges`.`owner_id`

MySql how to combine LEFT JOIN query with NOT IN query

I need to combine LEFT JOIN query with NOT IN query and have to get the result values from these queries. I have get the correct results while using these two queries at separately.
I have two tables likely user and answer
user table
user_id
1
2
3
4
5
answer table
user_id date
1 2015-10-15 21:23:14
2 2015-10-15 20:23:14
3 2015-11-11 16:23:14
LEFT JOIN query:
SELECT user.user_id
FROM user
LEFT JOIN answer
ON user.user_id = answer.user_id
WHERE DATEDIFF(NOW(),answer.date) > 5
This query returns result user_id 1,2.
NOT IN query:
SELECT user.user_id
FROM user
WHERE user.user_id NOT IN (SELECT answer.user_id FROM answer)
This query returns result user_ids 4, 5.
I need to combine this two queries into single query so I tried with these two below queries:
SELECT user.user_id
FROM user
LEFT JOIN answer
ON user.user_id = answer.user_id
WHERE (DATEDIFF(NOW(),answer.date) > 5
AND user.user_id NOT IN (SELECT answer.user_id FROM answer))
and
SELECT user.user_id
FROM user
LEFT JOIN answer
ON user.user_id = answer.user_id
WHERE user.user_id NOT IN (SELECT answer.user_id FROM answer)
AND DATEDIFF(NOW(),answer.date) > 5
But these return empty user_id.
Edit
Expected result should contain values of 1,2,4,5
If your meaning is about to combine 2 selection together Try Union All / Union :
SELECT * FROM
(
SELECT [WITH YOUR LEFT JOIN STATEMENT]
UNION
SELECT [WITH YOUR NOT IN STATEMENT]
) ResultTABLE
If you refer to the answer table in the WHERE clause, the answer.date will be restricted to non-NULL value, making the LEFT JOIN behave like a regular join. Move the condition to the ON condition to retrieve all the users, plus maybe the matching rows in answers:
SELECT user.user_id
FROM user u
LEFT JOIN answer a ON u.user_id = a.user_id
AND DATEDIFF(NOW(),a.date) < 5
;
Edit: after the edit of the question it appears the OP wants joined records with non existing answer OR answer.date too old/young:
SELECT user.user_id
FROM user u
LEFT JOIN answer a ON u.user_id = a.user_id
WHERE a.date IS NULL -- no answer record
OR DATEDIFF(NOW(),a.date) > 5 -- too old answer record
;
Final version: Since the OP wants to find users who don't have a (recent) answer, the query can be simplified to:
SELECT user.user_id
FROM user u
WHERE NOT EXISTS (
SELECT * FROM answer a
WHERE a.user_id = u.user_id
AND DATEDIFF(NOW(), a.date) <= 5
);

Find unique values that do not exist in multiple columns and tables

A misconfigured manual import imported our entire AD into our help desk user database, creating a bunch of extraneous/duplicate accounts. Of course, no backup to restore from.
To facilitate the cleanup, I want to run a query that will find users not currently linked to any current or archived tickets. I have three tables, USER, HD_TICKET, and HD_ARCHIVE_TICKET. I want to compare the ID field in USER to the OWNER_ID and SUBMITTER_ID fields in the other two tables, returning the only the values in USER.ID that do not exist in any of the other four columns.
How can this be accomplished?
Do a left join for each relationship where the right table id is null:
select user.*
from user
left join hd_ticket on user.id = hd_ticket.owner_id
left join hd_ticket as hd_ticket2 on user.id = hd_ticket2.submitter_id
left join hd_archive_ticket on user.id = hd_archive_ticket.owner_id
left join hd_archive_ticket as hd_archive_ticket2 on user.id = hd_archive_ticket2.submitter_id
where hd_ticket.owner_id is null
and hd_ticket2.submitter_id is null
and hd_archive_ticket.owner_id is null
and hd_archive_ticket2.submitter_id is null
How about something like:
SELECT id
FROM user
WHERE id NOT IN
(
SELECT owner_id
FROM hd_ticket
UNION ALL
SELECT submitter_id
FROM hd_ticket
UNION ALL
SELECT owner_id
FROM hd_archive_ticket
UNION ALL
SELECT submitter_id
FROM hd_archive_ticket
)
If I understood you situation I would do this:
SELECT a.id FROM user a, hd_ticket b, hd_archive_ticket c WHERE a.id != b.id AND a.id != c.id
You would want to try something like below. Inner query where I am doing Inner join with other 2 tables, will return only those user id which exist in all 3 tables. Then in your outer query I am just filtering out those ID's returned by inner query; since your goal is to get only those USER ID which is not present in other tables.
select ID
FROM USER
WHERE ID NOT IN
(
select u.ID
from user u
inner join HD_TICKET h on u.ID = h.OWNER_ID
inner join HD_ARCHIVE_TICKET ha on u.ID = ha.SUBMITTER_ID
)

Finding data that's missing from the database

I need to figure out some clever MySQL snippet that will allow me to easily see two tables, the ids in the table if they exist or NULL or empty if they don't exist.
I have a users table and a legacy table and outside of manual comparison I can't figure out how to make them appear in a table together so I can compare. What I would love to see is something like this:
+----------------------------+
| user_id | email | uid |
| 14 | me#me.com | 26 |
| 16 | ug#ug.com | NULL |
+----------------------------+
I know there's a way to include NULL or empty values but I'm not sure what it is. Here's my deranged SQL query so far, yes, I know it's horrible to do subselects inside of subselects:
select uid from users where mail IN (
select email from legacy_users where id NOT IN (
select sourceid from migrate_map_users
)
);
There are three tables involved here, legacy_users => migrate_map_users => users. The middle is just an m2m which joins the two. legacy_users and users both have an email column. and their own version of an id.
Thank you all!
You need to learn about join types, in particular left and outer joins:
SELECT u.uid, u.mail, lu.id
FROM users u
LEFT OUTER JOIN legacy_users lu
ON u.email = lu.mail
WHERE lu.id NOT IN
(
SELECT sourceid
FROM migrate_map_users
);
The LEFT OUTER JOIN will make sure all records in the LEFT table will be returned, whether there is a corresponding one in the right one or not.
??
select u.uid, u.mail, l.email, l.id
from users u
left outer join legacy_users
on u.mail = l.email
-- two queries to get you going
select u.uid, u.mail, l.email, l.id
from users u
left outer join legacy_users
on u.mail = l.email
Where l.id is null
select l.email, l.id, u.uid, u.mail
from legacy_users l
left outer join users u
on l.email = u.mail
Where u.uid is null
Thanks to Oded's answer this is what I ended up with:
SELECT *
FROM (
SELECT id, mail, uid
FROM users
LEFT OUTER JOIN
legacy_users lu ON users.mail = lu.email
UNION DISTINCT
SELECT id, email, uid
FROM users
RIGHT OUTER JOIN
legacy_users lu ON users.mail = lu.email
) j
WHERE uid IS NULL
OR id IS NULL;
This also allowed me to do a where on the results. Bonus.
Note that it's using mail in the left join and email in the right join. Since mail wouldn't exist in the right outer join we have to use the email column from legacy_users and vice versa.