SQL Joins
Posted: May 8th, 2009 | Author: Christopher Vigliotti | Filed under: SQL | 4 Comments »Having spent most of my career working in environments where SQL development and ColdFusion development are handled by separate people or teams. The end result is that my SQL skills are not as evolved as my ColdFusion skills.
At my current job I am the one who writes the SQL for the small and medium-sized ColdFusion & SQL Server-based systems that I develop. Up until the other day I used implicit inner joins and over-used subqueries to get the data that I wanted from a database. My code worked, but it was ugly.
Ah Ha!
My SQL deficiency became apparent as I was sharing some code with a comrade yesterday. I was informed that my code had an “implicitly defined SQL Join”, and was informed that this style of coding is both deprecated and bad form. I was writing my queries like this…
SELECT c.cheeseId, c.name, o.name AS 'odorName' FROM Cheeses c, Odors o WHERE c.odorId = o.odorId
…but as it turns out I should be writing them like this…
SELECT c.cheeseId, c.name, o.name AS 'odorName' FROM Cheeses c INNER JOIN Odors o ON c.odorId = o.odorId
Both queries will return the same results, but the latter is well formed, and consistent with other join types that you may have in your application.
Once I understood that, a lightbulb appeared over my head. I kicked out a few more code samples to observe the results of left and right joins (a concept that I have been having problems grasping).
Left Joins In The House
SELECT c.cheeseId, c.name, o.name AS 'odorName' FROM Cheeses c LEFT JOIN Odors o ON c.odorId = o.odorId
The above SQL will return all cheeses and their associated odors. Cheeses that don’t have an odor will also be returned with a null value in the odorName column.
Right Joins In The House
SELECT c.cheeseId, c.name, o.name AS 'odorName' FROM Cheeses c RIGHT JOIN Odors o ON c.odorId = o.odorId
The above SQL will return all odors and the cheeses that they relate to. Odors that don’t link to an associated cheese will also be returned with a null value in the cheeseId and name columns.
It’s interesting how not understanding one bit of theory or syntax can act as a closed door in your mind that keeps you from understanding a whole world of knowledge. This is why I always maintain an open mind and take a bit of time each day to read other developer’s blogs.
Good explanation.
It helped me a lot when I thought of joins as Venn Diagrams (overlapping circles). http://en.wikipedia.org/wiki/Venn_diagram The left and right refer to order the tables are listed in.
If the tables are thought of as partially overlapping circles, the overlaps are where they ‘join’. The key word left and right is saying ‘get all on the left’ or ‘all on the right’, but only the other where they overlap. Thus an inner join gets only the overlap.
These two queries return identical results (note the order of tables and the corresponding left and right key words):
select a.col1, b.col2
from tableA a
right outer join tableB b
on b.pkid = a.fkid
select a.col1, b.col2
from tableB b
left outer join tableA a
on b.pkid = a.fkid
Thanks for the insight. I guess one person’s right outer join is one personls left outer join!
And if you create an unclustered index on c.odorId, your query performance will increase. Also, you should look into defining foreign keys for database integrity.
I’m with you on defining foreign keys, check out my more recent post on creating the database that this post references >> http://code.christophervigliotti.com/index.php/2009/05/creating-a-cheesy-database/
Reading up on “clustered index” vs “unclustered index” now. Feel free to drop me a link or two.