Joining three tables in SQL, Inner join does not work properly - mysql

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.

Related

JOIN subquery and different reault

I was writing an exercise about "Write a query to find the names (first_name, last_name) of the employees who are not supervisors"
I write it on my own and when i check the result or both, mine has less rows than the other.
I was using the JOIN function and the other doesn't.
I want help to know why two results are so different.
Thanks
the one i use join
SELECT
first_name, last_name
FROM
employees AS E
JOIN
departments AS D ON E.department_id = D.department_id
WHERE
NOT EXISTS( SELECT
0
FROM
departments
WHERE
E.manager_id = D.manager_id)
order by last_name;
the one doesn't use join
SELECT
b.first_name, b.last_name
FROM
employees b
WHERE
NOT EXISTS( SELECT
0
FROM
employees a
WHERE
a.manager_id = b.employee_id);
The big problem is that the NOT EXISTS subquery is referencing rows from the joined table. The manager_id column is qualified with D., and that's a reference to the joined table, not the table in the FROM clause of the subquery.
E.manager_id = D.manager_id
^^^^^^^ ^
We also suspect that an employee's supervisor is recorded in the employee row, as a reference to another row in the the employee table. But we don't have the schema definition or any example data, so we're just guessing.
It seems like there would be a supervisor_id in the employee table...
SELECT e.first_name
, e.last_name
, e.department_id
, d.department_id
FROM employees e
WHERE NOT EXISTS
( SELECT 1
FROM employees s
WHERE s.id = e.supervisor_id
)
ORDER
BY e.last_name
, e.first_name
It's also possible that some rows in employee have a value in the department_id column that don't have a matching row in the department table. If there is no matching row in department, the inner join will prevent the row from employee from being returned.
We can use an outer join when we want to return rows even when no matching row is found in the joined table. If we want to involve the departments table, because a "supervisor" is defined to be an employee that is the manager of a department, we can employ an anti-join pattern...
SELECT e.first_name
, e.last_name
FROM employees e
LEFT
JOIN departments d
ON d.manager_id = e.employee_id
WHERE d.manager_id IS NULL
ORDER
BY e.last_name
, e.first_name
Again, without a schema and some sample data, we're just guessing.
This query can be written using only Employees table, but in your query you have joined the employees table with department table. A query should be written with the minimal amount of tables that suffice your expected output, joining unnecessary tables may result in wrong out puts.
In this case you are joining Employees with department here what if there is no Department_ID in employee table for some employees, so those data will be dropped in the join and result won't be the expected.

I am unsure: Is this an anti-join?

I am working on the first problem of the famous SQLzoos and am working on the using Null section: http://sqlzoo.net/wiki/Using_Null
The question is:
List the teachers who have NULL for their department.
The corresponding SQL query would be:
SELECT t.name
FROM teacher t
WHERE t.dept IS NULL
Is this a type of anti-join? Specifically, is this a left-anti-join?
This isn't a join at all.
The statement is filtering only records for teachers who don't have an assigned department.
Set Difference
The set difference of teachers and departments, teacher \ department would be a kind of "anti-join"
SELECT
t.name
FROM teacher t
LEFT JOIN department d ON d.id = t.dept_id
WHERE d.id IS NULL
At first glance, this statement does what your statement does, if the foreign key reference was enforced, it would guarantee to do exactly that. However, one use for this statement would be to retrieve teachers who are assigned to departments that have since been deleted (e.g. if the English Lit Dept. & English as 2nd Lang Dept. were reorganized as the English Dept.)
Symmetric Difference
Another "anti-join" would be the symmetric difference, which selects elements from both sets ONLY if they cannot be joined, i.e
(teacher \ department) U (department \ teacher)
I can't think of a motivating example using teachers and departments, but one way to write the symmetric difference on databases that support the FULL OUTER JOIN would be:
SELECT
t.name
FROM teacher t
FULL OUTER JOIN department d ON d.id = t.dept_id
WHERE d.id IS NULL OR t.id IS NULL
For MySQL, this statement would have to be written as the union of two statements.
SELECT
t.name teacher_name, d.name department_name
FROM teacher t
LEFT JOIN department d ON d.id = t.dept_id
WHERE d.id IS NULL
UNION ALL
SELECT
t.name teacher_name, d.name department_name
FROM teacher t
LEFT JOIN department d ON d.id = t.dept_id
WHERE t.id IS NULL
Looking through one of my projects, I found this one use of symmetric difference:
Context:
I have three tables: users, users_gameplay_summary, users_transactions_summary. I needed to email those users who created their accounts in the past 7 days AND one of the following
have transacted but have not played or played but have not transacted.
To get the list, I have this query (note, this was written for Postgresql, and won't work on MySQL, but it illustrates the symmetric difference use case):
SELECT
COALESCE(g.user_id, t.user_id) user_id
FROM users_gameplay_summary g
FULL OUTER JOIN users_transactions_summary t ON t.user_id = g.user_id
WHERE COALESCE(g.user_id, t.user_id) IN (
SELECT user_id
FROM users
WHERE created_at > CURRENT_DATE - '7 day'::interval)
AND (g.user_id IS NULL OR t.user_id IS NULL)
Not exactly, your not actually joining anything now,
in the case of a left anti join you would have access to the department name as well. (although it would be NULL)
Your sql code would be a correct answer for the question you gave though.
A left anti join would be:
SELECT t.name
FROM teacher t
LEFT JOIN dept d ON d.id = t.dept
WHERE d.id IS NULL
To solve this problem of listing teachers without assigned departments, you don't need a JOIN between teacher and dept tables.
dept table is basically a dictionary table that you join to, to translate ids to corresponding names.
teacher table has a dept column which normally could have a FOREIGN KEY constraint to id column in dept table.
Your query is not an ANTI-JOIN. This is a simple projection and selection query using one table.
SELECT t.name
FROM teacher t
WHERE t.dept IS NULL
For an ANTI-JOIN you would at least need a JOIN operation between more than one table at first.
Normally an ANTI-JOIN could look like:
Using LEFT JOIN
SELECT *
FROM table1 t1
LEFT JOIN table2 t2
ON t1.join_column = t2.join_column
WHERE t2.join_column IS NULL
Using NOT EXISTS
SELECT *
FROM table1 t1
WHERE NOT EXISTS (
SELECT 1
FROM table2 t2
WHERE t1.join_column = t2.join_column
)

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)

mySQL- how to show all contact and their status by using INNER JOIN

This is my company Table
CompanyID, CompanyName
This is my Contact Table
ContactID, ContactName, CompanyID
This is my Report Table
ReportID, ReportName
This is my ReportContact Table, Many to Many Relationship
ContactID, ReportID
I want to return all ALL my CONTACTID of 1 company, include those who are not assign to any report, I also want to return the reportID that are assign to different contacts
1 contacts can be assign to many reports
1 reports can consist of many contacts
My current SQL CODE only manage to get the 2 contactID in the ReportContactTable
SELECT rc.ContactID, rc.ReportID from contact c INNER JOIN Reportcontact rc on c.ContactID = rc.ContactID Where CompanyID=1
how can Return all the contact include those not in the reportcontact table, but get the reportID at the same times?
INNER JOIN filters out those rows that are not in ReportContact. Try to use LEFT JOIN if you want all contacts from contact table.
SELECT rc.ContactID, rc.ReportID
FROM contact c LEFT JOIN Reportcontact rc
ON c.ContactID = rc.ContactID
WHERE CompanyID = 1
I'm not 100% sure I understand what you are trying to do, but if you want all rows from the contact table then you need to use an OUTER rather than INNER join.
Try changing the word INNER to LEFT.
An INNER join ensures that rows that satisfy the join condition appear in both tables.
An OUTER join says "show me all the rows in one table, plus those that satisfy the join condition from the other table". Which table shows all the rows depends on the use of the keywords LEFT and right
a left join b on a.id = b.id will show all rows from table a plus those from b which satisfy the join condition
a right join b on a.id = b.id will show all rows from table b plus those from a which satisfy the join condition

COUNT via multi-chain join

I have this hierarchy in my database (from lowest to highest):
User => Dept => Area => Company
Now I need to make a table that shows all companies (some info about them taken directly from companies table) but the last column in the HTML table I want to be Number of users. I know I need to join the tables together and perhaps join table to itself, but how do I do this?
Each of these tables have a column linking to its parent table (except Company ofc).
JOIN the tables:
SELECT
c.companyId,
c.CompanyName,
IFNULL(COUNT(u.userID), 0) AS 'Number Of Users'
FROM Company AS c
LEFT JOIN Area AS a ON c.CompanyID = a.CompanyID
LEFT JOIN Dept AS d ON a.DeptId = d.DeptId
LEFT JOIN users AS u ON D.UserId = u.UserId
GROUP BY c.companyId,
c.CompanyName;
Note that: LEFT JOIN with IFNULL will give you those companies that has no matched rows in the other tables; with count zero in this case