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.
Related
I have a huge performance issue with my below query I figured that what is the leakage but don't know how to go around it.
the issue is that inner selects go through all the records in tables which is like 200K and then try to select and apply the filter to it so the whole data get selected in the first round.
SELECT *
FROM (
SELECT
( SELECT GROUP_CONCAT(tp.login) login
FROM tp
WHERE tp.user_id = ue.user_id ) login,
u.email as email,
ue.fname as name
FROM user_extra ue
LEFT JOIN users u ON u.id = ue.user_id
) t
WHERE
email like '%sradesign.net#gmail.com%'
OR fname like '%test%'
OR login like '%461988%
Test does I have not made a mistake:
SELECT GROUP_CONCAT(tp.login) login,
u.email as email,
ue.fname as name
FROM user_extra ue
JOIN users u ON u.id = ue.user_id -- I doubt in LEFT
JOIN tp ON tp.user_id = ue.user_id
GROUP BY ue.fname,
u.email
-- , ue.user_id -- maybe needed, but I doubt
HAVING email like '%sradesign.net#gmail.com%'
OR fname like '%test%'
OR login like '%461988%
This is intermediate variant - it must be divided on two (or maybe three - depends on your data) separate queries combined with UNION later.
sometimes it happens that one user doesn't have any login(there is no record for him in tp table) but I want to show him if the customer search term matched in the email of fname how to do this? – Ali Mahmoudi
In such case this table must be joined using outer joining (LEFT JOIN). – Akina
with left join again become like before performance issue the query run for 200 Second – Ali Mahmoudi
As I have said above - this is intermediate variant. If it is correct then let's divide taking into account possible absence in tp:
SELECT GROUP_CONCAT(tp.login) login,
u.email as email,
ue.fname as name
FROM user_extra ue
JOIN users u ON u.id = ue.user_id -- I doubt in LEFT
LEFT JOIN tp ON tp.user_id = ue.user_id
WHERE u.email like '%sradesign.net#gmail.com%'
GROUP BY ue.fname,
u.email
UNION ALL
SELECT GROUP_CONCAT(tp.login) login,
u.email as email,
ue.fname as name
FROM user_extra ue
JOIN users u ON u.id = ue.user_id -- I doubt in LEFT
LEFT JOIN tp ON tp.user_id = ue.user_id
WHERE ue.fname like '%test%'
GROUP BY ue.fname,
u.email
UNION ALL
SELECT GROUP_CONCAT(tp.login) login,
u.email as email,
ue.fname as name
FROM user_extra ue
JOIN users u ON u.id = ue.user_id -- I doubt in LEFT
JOIN tp ON tp.user_id = ue.user_id
GROUP BY ue.fname,
u.email
HAVING login like '%461988%
Test its output for correctness.
If it will produce duplicates then replace UNION ALL with UNION DISTINCT.
You seem to have an extra layer of SELECTs. This causes an extra temp table that contains a huge amount of data.
Unnecessary use of LEFT adds confusion and may prevent some optimizations.
Leading wildcards prevent usage of index.
OR is hard to optimize. But...
A common trick for optimizing OR:
( SELECT ... WHERE email like '%sradesign.net#gmail.com%' )
UNION DISTINCT
( SELECT ... WHERE fname like '%test%' )
UNION DISTINCT
( SELECT ... WHERE login like '%461988% )
However, because of the JOINs, UNION may not be practical.
Consider using FULLTEXT instead of LIKE.
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.
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
)
So, the two tables in question:
userinfo: id(PK), users_id(FK to users table), name, surname
doctorpatient: id(PK), doctor_id(FK to users table), patient_id(FK to users table)
The idea is each doctor is assigned a few patients via the doctorpatient table. What I want to do is return an array of arrays, where each of the inner arrays contains this:
users_id(doctor), name(doctor), surname(doctor), users_id(patient), name(patient), surname(patient)
Can this even be done using purely SQL? I tried this:
SELECT userinfo.users_id,
userinfo.name,
userinfo.surname,
u2.users_id,
u2.name,
u2.surname
FROM doctorpatient
RIGHT OUTER JOIN userinfo
ON doctorpatient.doctor_id = userinfo.users_id
LEFT OUTER JOIN userinfo AS u2
ON doctorpatient.patient_id = u2.users_id
but no matter what combination of joins I try, it never comes out right. I tried getting the data in three separate queries and then somehow get the result I need using PHP, but I got nowhere with that.
Edit: What I want is this:
array(
subarray1(patient_id1,
patient_name1,
patient_surname1,
doctor_id1,
doctor_name1,
doctor_surname1)
subarray2(patient_id2,
patient_name2,
patient_surname2,
doctor_id1,
doctor_name1,
doctor_surname1)
etc...
where one doctor can have multiple patients. What my query gets me looks something like this:
array(
subarray1(patient_id1,
patient_name1,
patient_surname1,
)
subarray2(patient_id2,
patient_name2,
patient_surname2,
)
etc...
But most of the data is null.
I think a simple JOIN may be sufficient. The OUTER JOINs appear to be causing the null values because it tries to treat the doctors as patients.
SELECT u1.users_id AS doctor_id,
u1.name AS doctor_name,
u1.surname AS doctor_surname,
u2.users_id AS patient_id,
u2.name AS patient_name,
u2.surname AS patient_surname
FROM doctorpatient AS d JOIN userinfo AS u1 ON d.doctor_id = u1.users_id
JOIN userinfo AS u2 ON d.patient_id = u2.users_id
Try this:
SELECT
u.id as user_id,
u.name as user_name
u.surname as user_usrname
d.id as doc_id,
d.name as doc_name,
d.surname as doc_surname
FROM doctorpatient as dp
LEFT JOIN userinfo as u ON (dp.pacient_id = u.id)
LEFT JOIN userinfo as d ON (dp.doctor_id = d.id)
tbl_cmp
usr_id | cmp_name | usr_fname |cmp_addr
tbl_usr
cmp_usr_id |cmp_id | cmp_usr_fname | cnt_status
I am trying query retrieve data from both at a time for ::
retrieve all data from tbl_cmp
but
retrieve only field from tbl_usr that cnt_status=1
I tried this
SELECT *
FROM tbl_cmp
JOIN tbl_usr ON tbl_usr.cmp_id = tbl_cmp.usr_id
WHERE tbl_usr.cnt_status =1
but it shows only record that has cnt_status=1 not all record from first table
Try this
SELECT * FROM tbl_users LEFT JOIN tbl_cmp_user
ON tbl_cmp_user.cmp_id = tbl_users.usr_id
AND tbl_cmp_user.cnt_status =1
Use LEFT OUTER JOIN
SELECT *
FROM tbl_users
Left outer JOIN tbl_cmp_user
ON tbl_cmp_user.cmp_id = tbl_users.usr_id
and tbl_cmp_user.cnt_status =1
See Examples of left outer join here
What you really want is a cross join, because you do not have a join condition between the tables:
select c.*, u.*
from tbl_cmp c cross join
(select *
from tbl_users u
where u.cnt_status = 1
) u
You can express this without the subquery as:
select c.*, u.*
from tbl_cmp c cross join
tbl_users u
where u.cnt_status = 1
I prefer the subquery version, because it makes the condition on tbl_users quite apparent. In a more complicated query, the WHERE clause could be quite separated from where the table appears in the FROM clause.