inner joins in oracle - sql

I was thinking about the syntax of inner joins in Oracle's SQL implementation and here is something that seems a bit inconsistent:
Let's say you have two relations loan(loan_number, branch_name, amount) and borrower(customer_name, loan_number). loan_number is the attribute common to both tables. Now, Oracle gives you two ways to express an inner join:
select *
from loan, borrower
where loan.loan_number = borrower.loan_number;
The above statement is equivalent to:
select *
from loan
inner join borrower
on loan.loan_number = borrower.loan_number;
However, when expressing a cross join there is only one way to express it:
select *
from loan, borrower;
The following statement is syntactically incorrect:
select *
from loan
inner join borrower;
This is invalid; Oracle expects the ON... part of the clause
Given that an inner join is just a cross join with a filter condition, do you guys think that this is an inconsistency in Oracle's SQL implementation? Am I missing something?
I'd be interested in hearing some other opinions. Thanks.
As David pointed out in his answer the syntax is:
select *
from loan cross join borrower;
Even though I was not aware of the above syntax I still think it's inconsistent. Having the cross join keyword in addition to allowing inner join without a join condition would be fine. A cross join is in fact an inner join without a join condition, why not express it as an inner join without the join condition?

I would agree that it is not consistent.
But I would argue that the Oracle implementation is a good thing:
when you do a join, you almost always want to include a filter condition, therefore the ON part is mandatory.
If you really, really don't want to have a filter condition (are you really sure?), you have to tell Oracle explicitly with CROSS JOIN sytax.
Makes a lot of sense to me not to be 100% consistent - it helps to avoid you mistakes.

SELECT *
FROM Loan
CROSS JOIN Borrower
No inconsistency.

Oracle also supports the natural join syntax, which joins two tables on the basis of shared column name(s). This would work in your case because both tables have a column called LOAN_NUMBER.
SELECT *
FROM Loan
NATURAL JOIN Borrower
Now, your same argument could be made in this case, that the use of the keyword natural is strictly unnecessary. But if we follow the logic we end up with a situation in which this statement could be either a cross join or a natural join, depending on the column names:
SELECT *
FROM Loan
JOIN Borrower
This is clearly undesirable, if only because renaming LOAN.LOAN_NUMBER to LOAN_ID would change the result set.
So, there's your answer: disambiguation.

This way of expressing inner joins:
select * from loan, borrower where loan.loan_number = borrower.loan_number;
is not recommended for almost 20 years. It was kept because it is simply a valid expression that happens to convey an inner join. I would concentrate in using the version closer to the current standard, minimizing the chances for misunderstanding and flat out errors.

Related

SQL implicit join returns full join or Cartesian join?

I was watching the IBM SQL lecture on Coursera. And there is an example, Select * from Employees, Departments;
The professor mentioned that the outcome could be a full join or Cartesian join.
However, given my experience, I only have gotten the Cartesian join. Does anyone know when it will return the full join and depends on what condition?
Before the year 1992, the standard SQL syntax to produce the cartesian product of two tables was (note the absence of a WHERE clause):
select *
from Employees, Departments
If you add WHERE clause, you'll be adding a predicate that will reduce the number of selected rows, essentially defeating the purpose of producing a cartesian product.
Then SQL-92 defined a new [clearer] way of writing it using the CROSS JOIN clause:
select *
from Employees
cross join Departments
Both syntaxes will work on pretty much all database engines, but I would strongly recommend the latter since is clearer to read and to debug.
As a side note, I would recommend the professor to modernize himself/herself. SQL-92 happened 27 years ago as of today.
I think the answer lies in this question - what is the key difference between Full join and a Cross Join/cartesian join. Click Here to know the difference
A cross join cannot produce the same outcome as Full Join unless each table has not more than 2 records(<2) in it.

SQL INNER JOIN implemented as implicit JOIN

Recently, I came across an SQL query which looked like this:
SELECT * FROM A, B WHERE A.NUM = B.NUM
To me, it seems as if this will return exactly the same as an INNER JOIN:
SELECT * FROM A INNER JOIN B ON A.NUM = B.NUM
Is there any sane reason why anyone would use a CROSS JOIN here? Edit: it seems as if most SQL applications will automatically use a INNER JOIN here.
The database is HSQLDB
The older syntax is a SQL antipattern. It should be replaced with an inner join anytime you see it. Part of why it is an antipattern is because it is impoosible to tell if a cross join was intended or not if the where clasues is ommitted. This causes many accidental cross joins espcially in complex queries. Further, in some databases (espcially Sql server) the implict outer joins do not work correctly and so people try to combine explicit and implict joins and get bad results without even realizing it. All in all it is a poor practice to even consider using an implict join.
Yes, your both statements will return the same result. Which one is to be used is a matter of taste. Every sane database system will use a join for both if possible, no sane optimizer will really use a cross product in the first case.
But note that your first syntax is not a cross join. It is just an implicit notation for a join which does not specify which kind of join to use. Instead, the optimizer must check the WHERE clauses to determine whether to use an inner join or a cross join: If an applicable join condition is found in the WHERE clause, this will result in an inner join. If no such clause is found it will result in a cross join. Since your first example specifies an applicable join condition (WHERE A.NUM = B.NUM) this results in an INNER JOIN and thus exactly equivalent to your second case.

Commutativity of Inner Join

I read from this answer (click), the following conditional statements
Invoices.CustomerID=Customers.CustomerID
and
Customers.CustomerID=Invoices.CustomerID
are identical because it produces the same result set.
Now, my problem is about commutativity of inner join. I have tried both of the following approaches and they produce the same result set (except for the column order).
Customers table first
use MMABooks
select *
from Customers
inner join Invoices
on Invoices.CustomerID=Customers.CustomerID
where Customers.CustomerID=10
Invoices table first
use MMABooks
select *
from Invoices
inner join Customers
on Invoices.CustomerID=Customers.CustomerID
where Invoices.CustomerID=10
Questions
Is inner join commutative by design?
Is there a best practice that suggest or prefer one approach over the other one? I mean, which approach should I use?
It would be really weird if they didn't produce the same result. Did you expect a difference?
A best practice is to start with the table from which you select most of the columns.
You do have to worry about the order when you work with LEFT or RIGHT JOINS.

Whether to use JOIN or not? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
INNER JOIN versus WHERE clause — any difference?
SQL JOIN: is there a difference between USING, ON or WHERE?
For example, I have this SQL statement:
SELECT *
FROM orders, inventory
WHERE orders.product = inventory.product
or
SELECT *
FROM orders
JOIN inventory
ON orders.product = inventory.product
What is the difference between these two?
They do exactly the same thing, but I'd recommend the second approach for readability and maintainability.
Using JOIN allows you to separate the conditions that define relationships between tables from conditions which are filters on the result set.
Using JOIN makes it easier to see if you are missing a join condition.
Using JOIN allows you to easily choose between INNER or OUTER JOIN. The comma syntax is equivalent to INNER JOIN (though some databases do have an extension to allow an outer join when using the first approach).
The most important is to be consistent about which you use. The comma syntax has different precedence from the JOIN keyword which can lead to confusing errors if you try to mix the two syntaxes in the same query. Because of point 3, it is easier to be consistent if you always use JOIN.
Inner join is ansi syntax, should be the preferred method.
Imagine how ugly this solution could get if you were to use the , with say many tables?
SELECT * FROM orders, inventory, products, logistics, accounting, materials, ...
Be kind to your future developers and anyone else looking at or maintaining this code use the JOIN syntax.
The comma (,) is equivalent to an CROSS JOIN. Using an explicit CROSS JOIN is more intuitive and recommended, as it can easily be changed to a LEFT JOIN, RIGHT JOIN, etc. Using CROSS JOIN is also ANSI-compliant.
They are functionally equivalent. The second one is 'newer'.

Queries that implicit SQL joins can't do?

I've never learned how joins work but just using select and the where clause has been sufficient for all the queries I've done. Are there cases where I can't get the right results using the WHERE clause and I have to use a JOIN? If so, could someone please provide examples? Thanks.
Implicit joins are more than 20 years out-of-date. Why would you even consider writing code with them?
Yes, they can create problems that explicit joins don't have. Speaking about SQL Server, the left and right join implicit syntaxes are not guaranteed to return the correct results. Sometimes, they return a cross join instead of an outer join. This is a bad thing. This was true even back to SQL Server 2000 at least, and they are being phased out, so using them is an all around poor practice.
The other problem with implicit joins is that it is easy to accidentally do a cross join by forgetting one of the where conditions, especially when you are joining too many tables. By using explicit joins, you will get a syntax error if you forget to put in a join condition and a cross join must be explicitly specified as such. Again, this results in queries that return incorrect values or are fixed by using distinct to get rid of the cross join which is inefficient at best.
Moreover, if you have a cross join, the maintenance developer who comes along in a year to make a change doesn't know if it was intended or not when you use implicit joins.
I believe some ORMs also now require explicit joins.
Further, if you are using implied joins because you don't understand how joins operate, chances are high that you are writing code that, in fact, does not return the correct result because you don't know how to evaluate what the correct result would be since you don't understand what a join is meant to do.
If you write SQL code of any flavor, there is no excuse for not thoroughly understanding joins.
Yes. When doing outer joins. You can read this simple article on joins. Joins are not hard to understand at all so you should start learning (and using them where appropriate) right away.
Are there cases where I can't get the right results using the WHERE clause and I have to use a JOIN?
Any time your query involves two or more tables, a join is being used. This link is great for showing the differences in joins with pictures as well as sample result sets.
If the join criteria is in the WHERE clause, then the ANSI-89 JOIN syntax is being used. The reason for the newer JOIN syntax in the ANSI-92 format, is that it made LEFT JOIN more consistent across various databases. For example, Oracle used (+) on the side that was optional while in SQL Server you had to use =*.
Implicit join syntax by default uses Inner joins. It is sometimes possible to modify the implicit join syntax to specify outer joins, but it is vendor dependent in my experience (i know oracle has the (-) and (+) notation, and I believe sqlserver uses *= ). So, I believe your question can be boiled down to understanding the differences between inner and outer joins.
We can look at a simple example for an inner vs outer join using a simple query..........
The implicit INNER join:
select a.*, b.*
from table a, table b
where a.id = b.id;
The above query will bring back ONLY rows where the 'a' row has a matching row in 'b' for it's 'id' field.
The explicit OUTER JOIN:
select * from
table a LEFT OUTER JOIN table b
on a.id = b.id;
The above query will bring back EVERY row in a, whether or not it has a matching row in 'b'. If no match exists for 'b', the 'b' fields will be null.
In this case, if you wanted to bring back EVERY row in 'a' regardless of whether it had a corresponding 'b' row, you would need to use the outer join.
Like I said, depending on your database vendor, you may still be able to use the implicit join syntax and specify an outer join type. However, this ties you to that vendor. Also, any developers not familiar wit that specialized syntax may have difficulty understanding your query.
Any time you want to combine the results of two tables you'll need to join them. Take for example:
Users table:
ID
FirstName
LastName
UserName
Password
and Addresses table:
ID
UserID
AddressType (residential, business, shipping, billing, etc)
Line1
Line2
City
State
Zip
where a single user could have his home AND his business address listed (or a shipping AND a billing address), or no address at all. Using a simple WHERE clause won't fetch a user with no addresses because the addresses are in a different table. In order to fetch a user's addresses now, you'll need to do a join as:
SELECT *
FROM Users
LEFT OUTER JOIN Addresses
ON Users.ID = Addresses.UserID
WHERE Users.UserName = "foo"
See http://www.w3schools.com/Sql/sql_join.asp for a little more in depth definition of the different joins and how they work.
Using Joins :
SELECT a.MainID, b.SubValue AS SubValue1, b.SubDesc AS SubDesc1, c.SubValue AS SubValue2, c.SubDesc AS SubDesc2
FROM MainTable AS a
LEFT JOIN SubValues AS b ON a.MainID = b.MainID AND b.SubTypeID = 1
LEFT JOIN SubValues AS c ON a.MainID = c.MainID AND b.SubTypeID = 2
Off-hand, I can't see a way of getting the same results as that by using a simple WHERE clause to join the tables.
Also, the syntax commonly used in WHERE clauses to do left and right joins (*= and =*) is being phased out,
Oracle supports LEFT JOIN and RIGHT JOIN using their special join operator (+) (and SQL Server used to support *= and =* on join predicates, but no longer does). But a simple FULL JOIN can't be done with implicit joins alone:
SELECT f.title, a.first_name, a.last_name
FROM film f
FULL JOIN film_actor fa ON f.film_id = fa.film_id
FULL JOIN actor a ON fa.actor_id = a.actor_id
This produces all films and their actors including all the films without actor, as well as the actors without films. To emulate this with implicit joins only, you'd need unions.
-- Inner join part
SELECT f.title, a.first_name, a.last_name
FROM film f, film_actor fa, actor a
WHERE f.film_id = fa.film_id
AND fa.actor_id = a.actor_id
-- Left join part
UNION ALL
SELECT f.title, null, null
FROM film f
WHERE NOT EXISTS (
SELECT 1
FROM film_actor fa
WHERE fa.film_id = f.film_id
)
-- Right join part
UNION ALL
SELECT null, a.first_name, a.last_name
FROM actor a
WHERE NOT EXISTS (
SELECT 1
FROM film_actor fa
WHERE fa.actor_id = a.actor_id
)
This will quickly become very inefficient both syntactically as well as from a performance perspective.