Joins & Set Operations
Why join tables?
A good database keeps data in separate related tables (to avoid repetition). To answer “which department and floor does Pari work on?” we must combine rows of two tables – this is a join.
Sample tables
SELECT * FROM DEPT;
+-------+-------+-------+ | DCode | DName | Floor | +-------+-------+-------+ | D1 | Sales | 1 | | D2 | IT | 3 | | D3 | HR | 2 | +-------+-------+-------+
SELECT * FROM STAFF;
+-----+-------+--------+-------+ | SID | SName | Salary | DCode | +-----+-------+--------+-------+ | 1 | Neel | 40000 | D1 | | 2 | Ojas | 65000 | D2 | | 3 | Pari | 52000 | D2 | | 4 | Qasim | 38000 | D3 | +-----+-------+--------+-------+
Cartesian product
Listing two tables in FROM without a condition pairs every row of the first with every row of the second. Rows = 4 × 3 = 12; degree = 4 + 3 = 7. Most pairs are meaningless.
SELECT SName, DName FROM STAFF, DEPT ORDER BY SName, DName;
+-------+-------+ | SName | DName | +-------+-------+ | Neel | HR | | Neel | IT | | Neel | Sales | | Ojas | HR | | Ojas | IT | | Ojas | Sales | | Pari | HR | | Pari | IT | | Pari | Sales | | Qasim | HR | | Qasim | IT | | Qasim | Sales | +-------+-------+
SELECT COUNT(*) AS 'Rows in STAFF x DEPT' FROM STAFF, DEPT;
+----------------------+ | Rows in STAFF x DEPT | +----------------------+ | 12 | +----------------------+
Equi-join
Add a condition that the common column is equal. Use table.column when a column name exists in both tables.
SELECT SName, Salary, DName FROM STAFF, DEPT WHERE STAFF.DCode = DEPT.DCode ORDER BY SName;
+-------+--------+-------+ | SName | Salary | DName | +-------+--------+-------+ | Neel | 40000 | Sales | | Ojas | 65000 | IT | | Pari | 52000 | IT | | Qasim | 38000 | HR | +-------+--------+-------+
JOIN … ON and aliases
Short aliases (S, D) make queries shorter. JOIN … ON is the modern way of writing the same equi-join.
SELECT S.SName, D.DName, D.Floor FROM STAFF S JOIN DEPT D ON S.DCode = D.DCode WHERE D.Floor > 1 ORDER BY S.SName;
+-------+-------+-------+ | SName | DName | Floor | +-------+-------+-------+ | Ojas | IT | 3 | | Pari | IT | 3 | | Qasim | HR | 2 | +-------+-------+-------+
Natural join
NATURAL JOIN automatically joins on columns with the same name and shows the common column once.
SELECT * FROM STAFF NATURAL JOIN DEPT ORDER BY SID;
+-------+-----+-------+--------+-------+-------+ | DCode | SID | SName | Salary | DName | Floor | +-------+-----+-------+--------+-------+-------+ | D1 | 1 | Neel | 40000 | Sales | 1 | | D2 | 2 | Ojas | 65000 | IT | 3 | | D2 | 3 | Pari | 52000 | IT | 3 | | D3 | 4 | Qasim | 38000 | HR | 2 | +-------+-----+-------+--------+-------+-------+
Join with GROUP BY
SELECT D.DName, COUNT(*) AS Staff, SUM(S.Salary) AS Total FROM STAFF S, DEPT D WHERE S.DCode = D.DCode GROUP BY D.DName ORDER BY D.DName;
+-------+-------+--------+ | DName | Staff | Total | +-------+-------+--------+ | HR | 1 | 38000 | | IT | 2 | 117000 | | Sales | 1 | 40000 | +-------+-------+--------+
Set operations
Set operations combine the results of two SELECTs with the same number and type of columns.
SELECT Name FROM CLUB_A UNION SELECT Name FROM CLUB_B;
+-------+ | Name | +-------+ | Asha | | Ravi | | Neha | | Zoya | | Kabir | +-------+
SELECT Name FROM CLUB_A UNION ALL SELECT Name FROM CLUB_B;
+-------+ | Name | +-------+ | Asha | | Ravi | | Neha | | Ravi | | Zoya | | Neha | | Kabir | +-------+
MySQL 8.0.31+ also has INTERSECT and EXCEPT. The portable way, shown below, uses IN and NOT IN.
SELECT Name FROM CLUB_A WHERE Name IN (SELECT Name FROM CLUB_B);
+------+ | Name | +------+ | Ravi | | Neha | +------+
SELECT Name FROM CLUB_A WHERE Name NOT IN (SELECT Name FROM CLUB_B);
+------+ | Name | +------+ | Asha | +------+
Practice
- Table A has 5 rows and 3 columns, B has 4 rows and 2 columns. Degree and cardinality of A × B? Degree 5, cardinality 20.
- Show staff names with their floor for staff earning more than 50000. SELECT SName, Floor FROM STAFF S, DEPT D WHERE S.DCode = D.DCode AND Salary > 50000;
