Table 1 :- tbl_contacts
Fields
user_id
contact_id
first_name
last_name
Table 2 :- tbl_phone_details
Fields
contact_id
phone_number
phone_type
Table 3 :- tbl_email_details
Fields
contact_id
email_address
email_type
QUERY -
SELECT
tbl_contacts.*, tbl_email_details.*, tbl_phone_details.*
FROM
tbl_contacts, tbl_email_details,
tbl_phone_details
WHERE
tbl_contacts.user_id = '1'
I want to get first_name, last_name, Phone and Email details of particular user_id. I have used above query but its giving me repeated results and I am having less knowledge on DB queries like JOIN and INNER QUERY.
If anyone has any idea, please kindly help.
OUTPUT NEEDED:-
contact_id, first_name, last_name, phone_number, phone_type, email_address, email_type
(Here email and phone number can have 1 or more values for particular users).
Try like this
If you want to retrieve data for particular ID
SELECT T.contact_id,
T.first_name,
T.last_name,
P.phone_number,
P.phone_type,
E.email_address,
E.email_type
FROM tbl_contacts T LEFT JOIN tbl_phone_details P ON
T.contact_id = P.contact_id
LEFT JOIN tbl_email_details E ON
T.contact_id = E.contact_id
WHERE T.contact_id = #contact_id
If you want to retrieve all data
SELECT T.contact_id,
T.first_name,
T.last_name,
P.phone_number,
P.phone_type,
E.email_address,
E.email_type
FROM tbl_contacts T LEFT JOIN tbl_phone_details P ON
T.contact_id = P.contact_id
LEFT JOIN tbl_email_details E ON
T.contact_id = E.contact_id
SELECT tbl_contacts.*, tbl_email_details.*, tbl_phone_details.* FROM
tbl_contacts, tbl_email_details, tbl_phone_details WHERE
tbl_contacts.user_id = '1'
You forgot to mention the condition by which you are going to join all the tables!
SELECT c.first_name, c.last_name, p.phone_number, e.email_address
FROM tbl_contacts c, tbl_email_details e, tbl_phone_details p
WHERE tbl_contacts.user_id = '1'
AND c.contact_id = e.contact_id
AND e.contact_id = p.contact_id;
SELECT c.contact_id, c.first_name, c.last_name,
phone.phone_number, phone.phone_type,
email.email_address, email.email_type
FROM tbl_contacts c
LEFT JOIN tbl_email_details email ON c.contact_id = email.contact_id
LEFT JOIN tbl_phone_details phone ON c.contact_id = phone.contact_id
WHERE tbl_contacts.user_id = '1'
Sql queries are easy to learn and write and they are very useful in getting the important data from database. Joins are used to basically fetch the data from two or more tables on the bases of common column in both tables.
Inner Join will select those values that are common in both of the tables.
Left Join will select all the data from the left table and Right Join will select all the data from right table on the basis of id.
These are the basics of SQL and you must know how to fetch accurate data using them.
this is how I would make that request with JOIN ... but there might be some better or faster way to do it.
SELECT first_name, last_name, phone_number, email_address
FROM tbl_contacts
JOIN tbl_phone_details
ON tbl_contacts.contact_id=tbl_phone_details.contact_id
JOIN tbl_email_details
ON tbl_email_details.contact_id=tbl_contacts.contact_id
WHERE tbl_contacts.user_id = '1';
And just so you don't get lost in all the different answers here (which are probably all correct):
you don't need to give an aliase name to your tables (it's just for readability)
you don't need to mention the table names in your column list if the column name is unique (e.g first_name is only in tbl_contacts). Just if you want the contact_id then you should decide which one (e.g. tbl_phone_details.contact_id)
the multi-select as Jayaram proposed, is exactly the same as the JOIN. MySQL handles both queries the same way (I just didn't see his answer when I responded, sorry)
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.
Let's say that I have two tables A and B where
A is table countries with columns id, name, created, modified
that contains a bunch of countries
And B is table users with columns id, first_name, last_name, email, country_id, created, modified
that contains a bunch of users linked to countries via foreign key country_id
What is the most efficient query to get all the countries that don't have a user with email address "myemail#test.com" associated to it?
I tried something like the following but that didn't work:
SELECT DISTINCT
c.*
FROM
countries c
LEFT JOIN
users u ON u.country_id = c.id
WHERE
u.email <> 'myemail#test.com'
Thanks for any help
NOTE I also tried putting the condition on the email column in the ON clause that didn't work either
A left join is fine, you just need to set it up correctly:
SELECT c.*
FROM countries c LEFT JOIN
users u
ON u.country_id = c.id AND u.email = 'myemail#test.com'
WHERE u.country_id IS NULL;
In terms of performance, this should be pretty similar to NOT EXISTS and NOT IN (although I do not recommend the latter because it has different behavior when there are NULL values).
When you say "that don't have a user with email address "myemail#test.com"",
do you mean no email address -or- not that exact email address?
Updated
Then this should do:
SELECT DISTINCT c.*
FROM countries c
LEFT JOIN users u ON u.country_id = c.id and u.email = 'myemail#test.com'
WHERE u.country_id is null
Which I believe is what Gordon already had.
Updated Again
In that case, try:
SELECT DISTINCT c.*
FROM countries c
INNER JOIN users u ON u.country_id = c.id and ISNULL(u.email, '') = ''
This looks for Null or Empty String email adresses all others are excluded from the join and therefore from the result set.
I hope this helps.
We have three tables, document,department and contact.
All the tables are linked by an 'id' column. I want the result as follows
firstname lastname address upload_date department_name
The below query fetches the first four columns
SELECT contact.firstname, contact.lastname,contact.address ,
document.upload_date
FROM contact
JOIN document
ON document.id= contact.id
AND contact.status = 1
AND document.defaultdoc=1
So it's an inner join.
But to fetch the last column, the department_name I added a similar join with contact.deptId=department.id, but the query returns zero results. Anything wrong ?
if you add
JOIN department
ON contact.deptId=department.id
it should work.
If all deptId's exist in its master table department then you can use below query:
SELECT c.firstname, c.lastname,c.address ,
doc.upload_date, d.department_name
FROM contact as c
JOIN document as doc
ON doc.id= c.id
AND c.status = 1
AND doc.defaultdoc=1
JOIN department as d
on c.deptId=d.id;
But if deptid updated in contact table does not exist in department table (which should not be if you want referential integrity in your db), then you can use below query:
SELECT c.firstname, c.lastname,c.address ,
doc.upload_date, d.department_name
FROM contact as c
JOIN document as doc
ON doc.id= c.id
AND c.status = 1
AND doc.defaultdoc=1
LEFT JOIN department as d
on c.deptId=d.id;
If both don't work then show your table data and structure.
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)
i have a MySQL SELECT query which fetches data from 6 tables using Mysql JOIN. here is the MySQL query i am using.
SELECT
u.id,u.password,
u.registerDate,
u.lastVisitDate,
u.lastVisitIp,
u.activationString,
u.active,
u.block,
u.gender,
u.contact_id,
c.name,
c.email,
c.pPhone,
c.sPhone,
c.area_id,
a.name as areaName,
a.city_id,
ct.name as cityName,
ct.state_id,
s.name as stateName,
s.country_id,
cn.name as countryName
FROM users u
LEFT JOIN contacts c ON (u.contact_id = c.id)
LEFT JOIN areas a ON (c.area_id = a.id)
LEFT JOIN cities ct ON (a.city_id = ct.id)
LEFT JOIN states s ON (ct.state_id = s.id)
LEFT JOIN countries cn ON (s.country_id = c.id)
although query works perfectly fine it sometimes returns duplicate results if it finds any duplicate values when using LEFT JOIN. for example in contacts table there exist two rows with area id '2' which results in returning another duplicated row. how do i make a query to select only the required result without any duplicate row. is there any different type of MySQL Join i should be using?
thank you
UPDATE :
here is the contacts table, the column area_id may have several duplicate values.
ANSWER :
there was an error in my condition in last LEFT JOIN where i have used (s.country_id = c.id) instead it should be (s.country_id = cn.id) after splitting the query and testing individually i got to track the error. thank you for your response. it works perfectly fine now.
Duplicating the rows like you mentioned seems to indicate a data problem.
If users is your most granular table this shouldn't happen.
I'd guess, then, that it's possible for a single user to have multiple entries in contacts
You could use DISTINCT as mentioned by #dxprog but I think that GROUP BY is more appropriate here. GROUP BY whichever datapoint could potentially be duplicated....
After all, if a user has corresponding contact records, which one are you intending to JOIN to?
You must specify this if you want to remove "duplicates" because, as far as the RDBMS is concerned, the two rows matching
LEFT JOIN contacts c ON (u.contact_id = c.id)
Are, in fact, distinct already
I think a DISTINCT may be what you're looking for:
SELECT DISTINCT
u.id,u.password,
u.registerDate,
u.lastVisitDate,
u.lastVisitIp,
u.activationString,
u.active,
u.block,
u.gender,
u.contact_id,
c.name,
c.email,
c.pPhone,
c.sPhone,
c.area_id,
a.name as areaName,
a.city_id,
ct.name as cityName,
ct.state_id,
s.name as stateName,
s.country_id,
cn.name as countryName
FROM users u
LEFT JOIN contacts c ON (u.contact_id = c.id)
LEFT JOIN areas a ON (c.area_id = a.id)
LEFT JOIN cities ct ON (a.city_id = ct.id)
LEFT JOIN states s ON (ct.state_id = s.id)
LEFT JOIN countries cn ON (s.country_id = c.id)
This should only return rows where the user ID is distinct, though you may not get all the joined data you'd hoped for.