MySQL Join 3 tables by 2 columns ids in the first table - mysql

I have 3 tables... Contacts, Outbound Operator, Digital Operator.
The contacts table contains all the contacts generated by either outbound operator and digital operator.
So I will have these columns in "Contacts":
id, name, surname, id_outbound_operator, id_digital operator
In the second table I have all the outbound operators so the table is something like this:
uid, out_bound_operator_full_name
The third table is the same as the second but with these columns:
uid, digital_operator_full_name
I want to obtain something like this:
id, name, surname, outbound_operator_full_name (if this was generated by a outbound operator), digital_operator_full_name (if this was generated by a outbound operator).
I have to specify that in contacts table at lease one of the two
(id_outbound_operator/id_digital_operator) is not null
I tried this
SELECT CONTATTI.id, CONTATTI.nome_azienda, CONTATTI.telefono, CONTATTI.stato, CONTATTI.id_outbound, CONTATTI.id_digital_marketing_op, CONTATTI.blacklisted, OUTBOUND_INT_login.uid, OUTBOUND_INT_login.nome_completo, MARKETING_DIGITAL_login.uid, MARKETING_DIGITAL_login.nome_completo
FROM CONTATTI
JOIN OUTBOUND_INT_login
ON CONTATTI.id_outbound = OUTBOUND_INT_login.uid
JOIN MARKETING_DIGITAL_login
ON CONTATTI.id_digital_marketing_op = MARKETING_DIGITAL_login.uid
but it doesn't work properly

You should use a UNION of queries that join with each of the other tables.
SELECT c.id, c.name, c.surname, o.outbound_operator_full_name
FROM CONTATTI AS c
JOIN OUTBOUND_INT_login AS o ON c.id = o.uid
UNION ALL
SELECT c.id, c.name, c.surname, m.digital_operator_full_name
FROM CONTATTI AS c
JOIN MARKETING_DIGITAL_login AS m ON c.id = m.uid

You can join the three tables as follows. You want left join so that contact records that cannot joined with both outbound_operator and digital_operator are not eliminated from the resultset.
select
c.id,
c.name,
c.surname,
op.outbound_operator_full_name,
do.digital_operator_full_name
from contact c
left join outbound_operator op on c.id_outbound_operator = op.uid
left join digital_operator do on c.id_digital_operator = do.uid
As commented by Uueerdo, if you want a unique column with either the outbound_operator_full_name or the digital_operator_full_name, then:
select
c.id,
c.name,
c.surname,
coalesce(op.outbound_operator_full_name, do.digital_operator_full_name) operator_full_name
from contact c
left join outbound_operator op on c.id_outbound_operator = op.uid
left join digital_operator do on c.id_digital_operator = do.uid
The advantage of this approach is that it requires a single scan on contact, vs two scans when using UNION (ALL).

Related

SQL Join tables and show default value for unmatched records in the right table

I have 2 tables which I want them to be joined when certain condition has been met.
1) Clients Table
2) Payments Table
With these tables, I want to see how much each client has already paid.
If a client has no payments made yet, the amount column should be 0
I had this SQL query but it won't show the clients without payments.
SELECT c.id, c.name, co.amount FROM clients c LEFT OUTER JOIN collectibles co ON c.id = co.client_id WHERE co.removed = 0
The result of this query will only show 1 record and that is client Cliff with payment 25000
How will I be able to achieve the expected output?
You should not use left join table's column in where. this way work as inner join in these cases add the condition to the related ON clause
SELECT c.id
, c.name
, ifnull(co.amount ,0)
FROM clients c
LEFT OUTER JOIN collectibles co ON c.id = co.client_id
AND co.removed = 0
The WHERE clause turns the outer join into an inner join. I think you want:
SELECT c.id, c.name, COALESCE(co.amount, 0) as amount
FROM clients c LEFT OUTER JOIN
collectibles co
ON c.id = co.client_id AND co.removed = 0;
You need COALESCE()to return 0 instead of NULL.

Inner join not working. Output repeating rows

I'm trying to get the the students number & name with the course code & name for students who have a grade below 40. This is what i have
SELECT S.name, S.no, C.code, C.name, T.grade
FROM student S INNER JOIN course C INNER JOIN take T
WHERE grade <40;
It is outputting the grades under 40 but it is returning 128 rows showing everyone's name and number grade repeating them.
Sorry if this is wrong but im a beginner.
You need the conditions that relate the tables to each other:
SELECT S.name, S.no, C.code, C.name, T.grade
FROM student AS s
JOIN take AS t ON t.student_no = s.no
JOIN course AS c ON t.course_code = c.code
Replace student_no and course_code with the actual foreign key columns in the take table.
Simple syntax refer it
SELECT Orders.OrderID, Customers.CustomerName, Shippers.ShipperName
FROM ((Orders
INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID)
INNER JOIN Shippers ON Orders.ShipperID = Shippers.ShipperID);

SQL efficiency join on two fields or one

Let say that I have got three tables: account, contact and address. To account and contact I want to assign multiple addresses. Is it better to have two fields in address join_type and join_id and then for example running query:
SELECT a.*
FROM address a
INNER JOIN contact c ON c.id = a.join_id AND a.join_type = 'CONTACT';
and
SELECT a.*
FROM address a
INNER JOIN account ac ON ac.id = a.join_id AND a.join_type = 'ACCOUNT';
or have account_id and contact_id instead of join_type and join_id and running query:
SELECT a.*
FROM address a
INNER JOIN contact c ON c.id = a.contact_id;
and
SELECT a.*
FROM address a
INNER JOIN account ac ON ac.id = a.account_id;
or maybe even have got two seperate address tables for account and contact? The first option is the best for future if I would like e.g. have also addresses assigned to users.
SELECT a.*
FROM address a
INNER JOIN contact c ON c.id = a.contact_id;
The fact that you have multiple types of addresses should not cause any problem since the contact_id should always be unique.
I would also consider having another column in address with account_id and have another join like this:
SELECT a.*
FROM address a
INNER JOIN account a ON a.id = a.account_id;

Get data from multiple tables in MySQL

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)

Problem using MySQL Join

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.