The SELECT reserved word is part of the Data Manipulation Language (DML) defined by Codd and is used to query data from the database. Because of its popularity, there are many clauses and functions that can be used to construct a query to retrieve data.
Today, I am continuing our exploration of this reserved word by reviewing queries that merge data using joins and unions.
Six known join types exist in SQL Server. The definitions are based upon joining TABLE A (left) with TABLE B (right).
- Inner Join – Include matching rows from left and right tables equal joined on a key.
- Left Outer Join – Include all rows from left table and any matching rows from right table. Unmatched right rows are shown as null values.
- Right Outer Join – Include all rows from right table and any matching rows from left table. Unmatched left rows are shown as null values.
- Full Outer Join – Include all rows from left and right tables. Unmatched rows are shown as null values.
- Theta Join – Match rows between left and right tables using not-equal condition (<, >, <=, >=, <>).
- Cross Join – This is known as a cartesian product. Each row in left table is matched with all rows in right without any conditions.
We will be creating a simple AUTO database with two tables to show how joins work. TABLE A has cars that Alan owns and TABLE B has cars that John owns. This example does not conform to Normalization rules but defines primary keys for joining between the two tables. In the real world, one table would have a PRIMARY key and the other, a FOREIGN key.
The code snipet below creates this teaching database and populates it with data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<span style="color: #008000;font-family:Lucida Console;font-size:small;">-- Create a very basic database CREATE DATABASE AUTOS; GO -- Use the database USE [AUTOS] GO -- Person A Cars CREATE TABLE A ( MyId INT PRIMARY KEY CLUSTERED, MyValue VARCHAR(20) ) GO INSERT INTO A (MyId, MyValue) VALUES (1, 'Continental'), (2, 'Edsel'), (3, 'Lincoln'), (4, 'Mercury'), (5, 'Ram') GO -- Person B Cars CREATE TABLE B ( MyId INT PRIMARY KEY CLUSTERED, MyValue VARCHAR(20) ) GO INSERT INTO B (MyId, MyValue) VALUES (1, 'Continental'), (4, 'Mercury'), (5, 'Ram'), (6, 'Jeep'), (7, 'Plymouth'), (8, 'Dodge') GO</span> |
A venn diagram is an easy way to represent set operations. Click on the links below to see diagrams for selected joins. The empty set is when no records are in common between SET T1 and SET T2.
A INNER JOIN finds the records in common between TABLE A and TABLE B.
1 2 3 4 5 6 7 8 9 10 |
<span style="color: #008000;font-family:Lucida Console;font-size:small;">-- Inner Join - Find cars A & B have in common SELECT * FROM A INNER JOIN B ON A.MyId = B.MyId GO -- Output MyId MyValue MyId MyValue ----------- -------------------- ----------- -------------------- 1 Continental 1 Continental 4 Mercury 4 Mercury 5 Ram 5 Ram</span> |
A LEFT OUTER JOIN list all records that TABLE A has and matching records from TABLE B.
1 2 3 4 5 6 7 8 9 |
<span style="color: #008000;font-family:Lucida Console;font-size:small;">-- Left Join - Find cars A owns but B does not SELECT * FROM A LEFT OUTER JOIN B ON A.MyId = B.MyId WHERE B.MyId IS NULL GO -- Output MyId MyValue MyId MyValue ----------- -------------------- ----------- -------------------- 2 Edsel NULL NULL 3 Lincoln NULL NULL</span> |
A RIGHT OUTER JOIN list alls records that TABLE B has and matching records from TABLE A.
1 2 3 4 5 6 7 8 9 10 |
<span style="color: #008000;font-family:Lucida Console;font-size:small;">-- Right Join - Find cars B owns but A does not SELECT * FROM A RIGHT OUTER JOIN B ON A.MyId = B.MyId WHERE A.MyId IS NULL GO -- Output MyId MyValue MyId MyValue ----------- -------------------- ----------- -------------------- NULL NULL 6 Jeep NULL NULL 7 Plymouth NULL NULL 8 Dodge</span> |
A FULL OUTER JOIN is basically the UNION of a LEFT and RIGHT outer join with duplicates removed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span style="color: #008000;font-family:Lucida Console;font-size:small;">-- Full Outer Join - Show results of left and right join merged SELECT * FROM A FULL OUTER JOIN B ON A.MyId = B.MyId GO -- Output MyId MyValue MyId MyValue ----------- -------------------- ----------- -------------------- 1 Continental 1 Continental 2 Edsel NULL NULL 3 Lincoln NULL NULL 4 Mercury 4 Mercury 5 Ram 5 Ram NULL NULL 6 Jeep NULL NULL 7 Plymouth NULL NULL 8 Dodge</span> |
A CROSS JOIN is the cartesian product of TABLE A and TABLE B.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<span style="color: #008000;font-family:Lucida Console;font-size:small;">-- Cross Join - Join each row in A with a row in B SELECT * FROM A CROSS JOIN B GO -- Output MyId MyValue MyId MyValue ----------- -------------------- ----------- -------------------- 1 Continental 1 Continental 1 Continental 4 Mercury 1 Continental 5 Ram 1 Continental 6 Jeep 1 Continental 7 Plymouth 1 Continental 8 Dodge 2 Edsel 1 Continental 2 Edsel 4 Mercury 2 Edsel 5 Ram 2 Edsel 6 Jeep 2 Edsel 7 Plymouth 2 Edsel 8 Dodge 3 Lincoln 1 Continental 3 Lincoln 4 Mercury 3 Lincoln 5 Ram 3 Lincoln 6 Jeep 3 Lincoln 7 Plymouth 3 Lincoln 8 Dodge 4 Mercury 1 Continental 4 Mercury 4 Mercury 4 Mercury 5 Ram 4 Mercury 6 Jeep 4 Mercury 7 Plymouth 4 Mercury 8 Dodge 5 Ram 1 Continental 5 Ram 4 Mercury 5 Ram 5 Ram 5 Ram 6 Jeep 5 Ram 7 Plymouth 5 Ram 8 Dodge</span> |
A THETA JOIN is when the join condition is a non-equality. I have never used this join in the REAL WORLD; However, If you worked at Chucky Cheese and wanted to see all the items that your kid could get for earned game points, this join might come in handy. From the KIDS table, earned points would be a key that would be joined to the PRIZES table on point value where prize point value <= earn points. This query would give you the prize pool to pick from.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<span style="color: #008000;font-family:Lucida Console;font-size:small;">-- Theta Join - Not used often SELECT * FROM A JOIN B ON A.MyId >= B.MyId GO -- Output MyId MyValue MyId MyValue ----------- -------------------- ----------- -------------------- 1 Continental 1 Continental 2 Edsel 1 Continental 3 Lincoln 1 Continental 4 Mercury 1 Continental 4 Mercury 4 Mercury 5 Ram 1 Continental 5 Ram 4 Mercury 5 Ram 5 Ram</span> |
The UNION reserved word is used to join two simular sets of columns from two or more tables.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<span style="color: #008000;font-family:Lucida Console;font-size:small;">-- Combine two lists as one, dupes removed SELECT * FROM A UNION SELECT * FROM B GO -- Output MyId MyValue ----------- -------------------- 1 Continental 2 Edsel 3 Lincoln 4 Mercury 5 Ram 6 Jeep 7 Plymouth 8 Dodge</span> |
The default behavoir of the word is to remove duplicates. If you want to keep duplicates, add the ALL reserved word.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<span style="color: #008000;font-family:Lucida Console;font-size:small;">-- Combine two lists as one, dupes keep SELECT * FROM A UNION ALL SELECT * FROM B ORDER BY MyId GO -- Output MyId MyValue ----------- -------------------- 1 Continental 1 Continental 2 Edsel 3 Lincoln 4 Mercury 4 Mercury 5 Ram 5 Ram 6 Jeep 7 Plymouth 8 Dodge</span> |
The EXCEPT and INTERSECT reserved words are used to merge and compare records as a whole. You probably do not realize we did just this with the LEFT and RIGHT joins on key values.
The two snipets below use the EXCEPT clause to return unique cars.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<span style="color: #008000;font-family:Lucida Console;font-size:small;">-- What A has unique SELECT * FROM A EXCEPT SELECT * FROM B GO -- Output MyId MyValue ----------- -------------------- 2 Edsel 3 Lincoln -- What B has unique SELECT * FROM B EXCEPT SELECT * FROM A GO -- Output MyId MyValue ----------- -------------------- 6 Jeep 7 Plymouth 8 Dodge</span> |
The snipet below uses the INTERSECT clause to return common cars.
1 2 3 4 5 6 7 8 9 10 11 12 |
<span style="color: #008000;font-family:Lucida Console;font-size:small;">-- Common fields based on whole record, not just key SELECT * FROM A INTERSECT SELECT * FROM B GO -- Output MyId MyValue ----------- -------------------- 1 Continental 4 Mercury 5 Ram</span> |
To demonstate that the whole record, not just the PRIMARY key is used in the compare, I am going to change one column to the value test. As we can see, the results change from above. The snipet below restores the data to leave our example intack.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<span style="color: #008000;font-family:Lucida Console;font-size:small;">-- Change one record in table A UPDATE A SET MyValue = 'test' WHERE MyId = 1 GO -- Different results SELECT * FROM A INTERSECT SELECT * FROM B GO -- Restore value to one record UPDATE A SET MyValue = 'Continental' WHERE MyId = 1 GO -- Output MyId MyValue ----------- -------------------- 4 Mercury 5 Ram</span> |
To recap this discussion, JOINS are used to merge data horizontally by adding additional fields to the result set. UNIONS are used to merger the data vertically by stacking simular data together. The EXCEPT and INTERSECT operations return what is different and common between records from two tables. In short, these key words allow you to take NORMALIZED data combine it to return results that are important to your organization.
Next time I talk about the SELECT statement, I will be introducing functions that can be applied to the various datatypes.
awesome blog, do you have twitter or facebook? i will bookmark this page thanks.
Really fantastic information can be found on site.