INNER JOIN: only the rows that match in both tables.
LEFT JOIN: every row from the left table, plus matches from the right (NULL when there is none).
RIGHT JOIN: the mirror image: every row from the right table.
FULL JOIN: every row from both tables, NULL where there is no match.
CROSS JOIN: every left row paired with every right row.
11Basic
One query per join type
answer-1.sql
1-- INNER JOIN: matching rows only2SELECTe.name,d.nameASdepartment3FROMemployeese4INNERJOINdepartmentsdONe.department_id=d.id;56-- LEFT JOIN: every employee, even without a department7SELECTe.name,d.nameASdepartment8FROMemployeese9LEFTJOINdepartmentsdONe.department_id=d.id;1011-- RIGHT JOIN: every department, even without employees12SELECTe.name,d.nameASdepartment13FROMemployeese14RIGHTJOINdepartmentsdONe.department_id=d.id;1516-- FULL JOIN: every row from both tables17SELECTe.name,d.nameASdepartment18FROMemployeese19FULLJOINdepartmentsdONe.department_id=d.id;
Rows returned: INNER 4, LEFT 4, RIGHT 5, FULL 5
IT has no employees, so it only appears in RIGHT and FULL
22Optimized
Index the join key, return only what you need
answer-2.sql
1-- 1. Index the join key (PostgreSQL does not index foreign keys on its own)2CREATEINDEXidx_employees_department_idONemployees(department_id);34-- 2. Use the narrowest join and only the columns you need5SELECTe.name,d.nameASdepartment6FROMemployeese7JOINdepartmentsdONd.id=e.department_id;89-- 3. "Departments with no employees": anti-join instead of RIGHT JOIN + IS NULL10SELECTd.name11FROMdepartmentsd12WHERENOTEXISTS(SELECT1FROMemployeeseWHEREe.department_id=d.id);
Tip: use INNER JOIN unless you really need the unmatched rows
MySQL has no FULL JOIN: combine LEFT JOIN and RIGHT JOIN with UNION
Log in to mark questions completed and keep your streak.