SQL Join: Are selects between more than 2 tables still joins? - mysql

When I read about inner or outer joins in SQL, all examples and descriptions are about 2 tables being joined. What if there are more than 2 tables in the query? Is that still considered a join?
I think inner join still makes sense even if it is between multiple tables; but I'm not sure outer joins makes sense between more than 2 table.
Can someone please clarify this issue?

Inner joins and outer joins are perfectly reasonable to use with more than 2 tables.
Inner joins force the result to display only data that has whatever row you joined on, whereas outer joins display all data no matter what.
Let us say you wanted to join 4 tables together...
select * from testtable
inner join testable2 on col1 = othercolumn
inner join testable3 on col2 = othercolumn
leftjoin testable4 on col3 = othercolumn
In this case, it would return only results that existed in the inner joins, but the result would not have to exist in the outside/left join. You are forcing testtables 2 & 3 to have a value on what you are joining on.. it cannot be null.
The left join does not care if the value is null, and will show results anyway.
I hope this helps some... Basically.. if you inner join on a value, and it can possibly be null, then the entire query will show blank. This is the scenario you would use an outter join.. you are not forcing the value to exist.

Most examples of joins will include two tables. However, joins can be done on any number of tables.
You can read more about joins all over the interwebs, but you might want to start with:
http://www.w3schools.com/sql/sql_join.asp
http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
The w3schools article first thing stated is:
SQL joins are used to combine rows from two or more tables.
This isn't entirely true, as you can even join tables on themselvees!
Consider:
Employees
-----
EmployeeId
ManagerId
EmployeeName
if you want to find out the employees of a specific manager, that could be written as:
select manager.EmployeeName, subordinates.*
from employees manager
inner join employees subordinates on manager.employeeId = subordinates.managerId
For multiple table joins consider:
Employees
----
EmployeeId
ManagerId
EmployeeName
Departments
----
DepartmentId
DepartmentName
EmployeeDepartments
----
DepartmentId
EmployeeId
In this case, if you wanted to find out all department names that employee 5 belonged too, you could do:
select d.DepartmentName
from employees e
inner join employeeDepartments ed on e.employeeId = ed.employeeId
inner join departments d on ed.departmentId = d.departmentId
where e.employeeId = 5
TLDR; - yes including more than 2 tables is still considered join(s)

Every join clause is (logically) between two virtual tables but the virtual tables themselves can be defined as joins on further tables.
So in the following example
SELECT Foo
FROM A
INNER JOIN B
ON A.X = B.X
INNER JOIN C
ON C.Y = A.Y
AND C.Z = B.Z
it can be considered that logically A joins to B then the virtual table (A x B) is joined to C. Columns from all three of those tables are thus available in the final ON clause.
You can control the virtual tables that are evaluated by the placement of the ON clause.
The following example creates a virtual table (A x B) and a virtual table (C x D) and then joins these two together.
SELECT Foo
FROM A
INNER JOIN B
ON A.X = B.X
INNER JOIN C
INNER JOIN D
ON C.Y = D.Y /*Only C and D in scope here*/
ON A.Z = D.Z /*All tables back in scope*/
The query optimiser is free to actually implement the joins in any way that maintains the semantics however. As inner joins are commutative and associative the tables in the above example can be freely re-arranged. For outer joins re-arranging them could change the semantics.

Related

Cursor expression in MySQL

How do I achieve the same as an Oracle cursor expression does in a MySQL database (version from 5.6 onwards)
below is a sample query of an Oracle cursor expression
SELECT department_name, CURSOR(SELECT salary, commission_pct
FROM employees e
WHERE e.department_id = d.department_id)
FROM departments d;
How can I achieve the same as this with a MySQL database?
if i execute this query on oracle below output i will be produced,
depart_name cursor result
MCA { < SALARY=20000 , COMMISSION_PCT=2 > , < SALARY=40000,COMMISSION_PCT=20> ,}
BE {< SALARY=20000,COMMISSION_PCT=2 >,}
I don't know what a CURSOR() does in oracle because I've never touched oracle, but I don't know if it would help you but I think you wanted to join like this:
SELECT d.department_name, e.salary, e.commission_pct.
FROM departments d
INNER JOIN employees e
ON (e.department_id = d.department_id);
I give you this link for more information on joints:
https://sql.sh/cours/jointures
and according to sql.sh:
There are several methods to associate 2 tables together. Here is the
list of the different techniques that are used:
INNER JOIN: internal join to return the records when the condition is true in both tables. This is one of the most common
joins.
CROSS JOIN: cross join to make the Cartesian product of 2 tables. In other words, allows to join each row of a table with each
row of a second table. Attention, the number of results is
generally very high.
LEFT JOIN (or LEFT OUTER JOIN): external join to return all the records of the left table (LEFT = left) even if the condition is not
checked in the other table.
RIGHT JOIN (or RIGHT OUTER JOIN): External join to return all records in the right-hand table (RIGHT = right) even if the condition
is not checked in the other table.
FULL JOIN (or FULL OUTER JOIN) : external join to return the results when the condition is true in at least one of the 2 tables.
SELF JOIN : allows to join a table with itself as if it were another table.
NATURAL JOIN : natural join between 2 tables if there is at least one column with the same name between the 2 SQL tables.
UNION JOIN: joint of union.
if you have any questions, I am available to answer them.

SQL inner join multiple tables with one query

I've a query like below,
SELECT
c.testID,
FROM a
INNER JOIN b ON a.id=b.ID
INNER JOIN c ON b.r_ID=c.id
WHERE c.test IS NOT NULL;
Can this query be optimized further?, I want inner join between three tables to happen only if it meets the where clause.
Where clause works as filter on the data what appears after all JOINs,
whereas if you use same restriction to JOIN clause itself then it will be optimized in sense of avoiding filter after join. That is, join on filtered data instead.
SELECT c.testID,
FROM a
INNER JOIN b ON a.id = b.ID
INNER JOIN c ON b.r_ID = c.id AND c.test IS NOT NULL;
Moreover, you must create an index for the column test in table c to speed up the query.
Also, learn EXPLAIN command to the queries for best results.
Try the following:
SELECT
c.testID
FROM c
INNER JOIN b ON c.test IS NOT NULL AND b.r_ID=c.testID
INNER JOIN a ON a.id=b.r_ID;
I changed the order of the joins and conditions so that the first statement to be evaluated is c.test IS NOT NULL
Disclaimer: You should use the explain command in order to see the execution.
I'm pretty sure that even the minor change I just did might have no difference due to the MySql optimizer that work on all queries.
See the MySQL Documentation: Optimizing Queries with EXPLAIN
Three queries Compared
Have a look at the following fiddle:
https://www.db-fiddle.com/f/fXsT8oMzJ1H31FwMHrxR3u/0
I ran three different queries and in the end, MySQL optimized and ran them the same way.
Three Queries:
EXPLAIN SELECT
c.testID
FROM c
INNER JOIN b ON c.test IS NOT NULL AND b.r_ID=c.testID
INNER JOIN a ON a.id=b.r_ID;
EXPLAIN SELECT c.testID
FROM a
INNER JOIN b ON a.id = b.r_id
INNER JOIN c ON b.r_ID = c.testID AND c.test IS NOT NULL;
EXPLAIN SELECT
c.testID
FROM a
INNER JOIN b ON a.id=b.r_ID
INNER JOIN c ON b.r_ID=c.testID
WHERE c.test IS NOT NULL;
All tables should have a PRIMARY KEY. Assuming that id is the PRIMARY KEY for the tables that it is in, then you need these secondary keys for maximal performance:
c: INDEX(test, test_id, id) -- `test` must be first
b: INDEX(r_ID)
Both of those are useful and "covering".
Another thing to note: b and a is virtually unused in the query, so you may as well write the query this way:
SELECT c.testID,
FROM c
WHERE c.test IS NOT NULL;
At that point, all you need is INDEX(test, testID).
I suspect you "simplified" your query by leaving out some uses of a and b. Well, I simplified it from there, just as the Optimizer should have done. (However, elimination of tables is an optimization that it does not do; it figures that is something the user would have done.)
On the other hand, b and a are not totally useless. The JOIN verify that there are corresponding rows, possibly many such rows, in those tables. Again, I think you had some other purpose.

How to select from multiple tables when some of the tables are empty in MySQL

I need to fetch data from 5 tables(all columns of each table) all have FK, which is PK of single table.
But some of the tables may have record may be empty.If data is present on the respective column/table it should return otherwise null/default value
There is one to many and one to one relations on the child tables with parent table.
I have tried so far
- UNION which has concern of same number of columns
- CROSS JOIN not returning any data
- SELECT ALL_COLUMN FROM ALL_TABLE WHERE TABLE.FK=ID Not returning any data
- LEFT JOIN working for 2 tables but not more than that
SELECT A.GENDER, B.BLOCKED_USER FROM t_macroworld_registration AS A
LEFT JOIN t_macroworld_blacklist AS B ON 1=1 WHERE A.ID=15
What are the possible ways I can implement this in a view in MySQL.
Outer join operations are the normative pattern...
SELECT ...
FROM a
LEFT JOIN b ON b.a_id = a.id
LEFT JOIN c ON c.a_id = a.id
LEFT JOIN d ON d.a_id = a.id
WHERE a.id = 15
It's important for the predicates on the outer joined tables to be in the ON clause and not the WHERE clause. If there's any predicate in the WHERE clause requires that a value from one of the outer joined tables be non-NULL, that will negate the "outerness" of the join, making it into an inner join.
The "big rock" problem with this the result when there are more than one matching rows in b, c and d. If there's five rows from b that match, and three rows from c that match, and two rows from b that match, it's going to look like a lot of duplicates. (5x3x2 = 30 rows to be returned, with a lot of duplicated data on those rows.)
Finally I have solved It,
I broke the whole thing into many select query based on FK from each table, so number of additional row returns and mapping has become easy.
Who ever is getting this kind of problem, if it is possible then break it into many select query instead of one.
SELECT
w.id,w.name,a.address,i.name,i.quantity
FROM
warehouse w
LEFT JOIN address AS a ON a.warehouse_id = w.id
LEFT JOIN item AS i ON i.warehouse_id = w.id
LEFT JOIN order AS o ON o.item_id = i.id
WHERE
w.id = 1
GROUP BY 1,2,3,4;
Will give you an overview of your stock and orders for your warehouses. This will also duplicate some results.
Assuming 2 warehouses, 1 address for each, 3 items per warehouse, 2 orders by item = 2 * 3 * 2 = 12 lines
I recommend adding your LEFT JOIN stage by stage and visualizing the result for each stage. You'll quickly understand why lines are multiplying.
Note the usage of foreign keys and ids in the tables to link the tables.
Good luck

Mysql `using` syntax for multiple tables and one joining column

Instead of
SELECT * FROM a, b, c
WHERE a.jid = b.jid AND b.jid = c.jid
or
SELECT * FROM a JOIN b USING(jid) JOIN c USING(jid)
I'd like to use something like:
SELECT * FROM a, b, c USING(jid)
This may not seem like much of a convenience but when my query runs accross 4 tables and perhaps more, this could be a real helper.
I.e. there's one column that unites quite a few tables in my database. Is there a way to query multiple tables by naming that column only once?
You can use NATURAL JOIN to automatically join the tables based on columns with the same name. However, you will need to make sure that jid will be the ONLY column with the same name, otherwise you will not get the results that you want.
A NATURAL JOIN is a JOIN operation that creates an implicit join clause for you based on the common columns in the two tables being joined. Common columns are columns that have the same name in both tables.
SELECT * FROM a
NATURAL JOIN b
NATURAL JOIN c;

How to match this using SQL?

I am using the 3 following tables:
First table
id
response
Second table
responseid
patientid
Third table
patientid
The relationship between first and second table is on id and responceid.
The relationship between third and second is on patientid.
Now I need to retrieve values from these tables like all values from first and third tables with the help of matching with patientid from second and 3rd table.
How can I do this?
Basically if all of the columns that defines their relationship are not nullable, then INNER JOIN will suffice. But if they are nullable and you still want to display all records from firstTB, you need to use LEFT JOIN instead of INNER JOIN.
SELECT a.*, b.*, c.*
FROM firstTB a
INNER JOIN secondTB b
ON a.ID = b.responceID
INNER JOIN thirdTB c
ON b.patientID = c.patientID
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
You're probably looking for INNER JOIN or JOIN in general:
SELECT
response.id,
response.responce,
patient.patientid
FROM
`response_table` as `response`
INNER JOIN
`relation_table` as `relation`
ON
relation.responceid = response.id
INNER JOIN
`patient_table` as `patient`
ON
relation.patientid = patient.patientid
try
SELECT first.*
, third.*
FROM first
INNER JOIN second ON ( second.responseid = first.id )
INNER JOIN third ON ( third.patientid = second.patientid )
;
honestly, and no insult intended, if you have difficulties in coming up with queries like this one on your own, consider some training on db basics and db development, the sooner the better (just hoping i haven't blundered myself ... ;-)).