Inner_outer_joins
Chapter 13: INNER JOIN & OUTER JOINs
Section titled βChapter 13: INNER JOIN & OUTER JOINsβDeep Dive into Join Types
Section titled βDeep Dive into Join Typesβ13.1 INNER JOIN Fundamentals
Section titled β13.1 INNER JOIN FundamentalsβINNER JOIN returns only the rows that have matching values in both tables.
INNER JOIN Flow ========================================================================
βββββββββββββββββββ βββββββββββββββββββ β Table A β β Table B β β (users) β β (orders) β β β β β β βββββββββββββββ β β βββββββββββββββ β β β id β name β β β β id β user_id β β β βββββΌβββββββββ€ β β βββββΌββββββββββ€ β β β 1 β Alice β β β β 1 β 1 β β β β 2 β Bob β β β β 2 β 1 β β β β 3 β Charlieβ β β β 3 β 2 β β β β 4 β David β β β β 4 β 5 β β β No match β βββββββββββββββ β β βββββββββββββββ β ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ β β βββββββββββββ¬ββββββββββββββββ β βΌ βββββββββββββββββββββββββββββββββββββββββββ β INNER JOIN Result β β (Only matching rows from both tables) β β β β user_id β name β order_id β amount β β βββββββββΌββββββββΌβββββββββββΌββββββββ β β 1 β Alice β 1 β 100.00 β β 1 β Alice β 2 β 50.00 β β 2 β Bob β 3 β 200.00 β β β βββββββββββββββββββββββββββββββββββββββββββBasic INNER JOIN Syntax
Section titled βBasic INNER JOIN Syntaxβ-- Sample tablesCREATE TABLE customers ( customer_id SERIAL PRIMARY KEY, name VARCHAR(100), email VARCHAR(255));
CREATE TABLE orders ( order_id SERIAL PRIMARY KEY, customer_id INTEGER REFERENCES customers(customer_id), order_total DECIMAL(10,2), order_date DATE DEFAULT CURRENT_DATE);
-- Insert sample dataINSERT INTO customers (name, email) VALUES ('Alice Johnson', 'alice@example.com'), ('Bob Smith', 'bob@example.com'), ('Charlie Brown', 'charlie@example.com');
INSERT INTO orders (customer_id, order_total) VALUES (1, 150.00), (1, 75.50), (2, 200.00), (2, 100.00), (3, 50.00);
-- Basic INNER JOINSELECT c.customer_id, c.name, o.order_id, o.order_totalFROM customers cINNER JOIN orders o ON c.customer_id = o.customer_id;
-- Result: Only customers with orders are returned13.2 LEFT OUTER JOIN
Section titled β13.2 LEFT OUTER JOINβLEFT OUTER JOIN returns all rows from the left table and matched rows from the right table. NULL values for columns where no match exists.
LEFT JOIN Flow ========================================================================
βββββββββββββββββββ βββββββββββββββββββ β Table A β β Table B β β (customers) β β (orders) β β β β β β βββββββββββββββ β β βββββββββββββββ β β β id β name β β β β id β cust_id β β β βββββΌβββββββββ€ β β βββββΌββββββββββ€ β β β 1 β Alice β β β β 1 β 1 β β β β 2 β Bob β β β β 2 β 1 β β β β 3 β Charlieβ β β β 3 β 2 β β β β 4 β David β β β β β β β β No orders β βββββββββββββββ β β βββββββββββββββ β ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ β β βββββββββββββ¬ββββββββββββββββ β βΌ βββββββββββββββββββββββββββββββββββββββββββ β LEFT JOIN Result β β (All from left + matches from right) β β β β cust_id β name β order_id β amount β β βββββββββΌβββββββββΌβββββββββββΌββββββββ β β 1 β Alice β 1 β 100.00 β β 1 β Alice β 2 β 50.00 β β 2 β Bob β 3 β 200.00 β β 3 β Charlieβ NULL β NULL β β No match β 4 β David β NULL β NULL β β No match β β βββββββββββββββββββββββββββββββββββββββββββLEFT JOIN Examples
Section titled βLEFT JOIN Examplesβ-- Find all customers, even those without ordersSELECT c.customer_id, c.name, COALESCE(COUNT(o.order_id), 0) as total_orders, COALESCE(SUM(o.order_total), 0) as total_spentFROM customers cLEFT JOIN orders o ON c.customer_id = o.customer_idGROUP BY c.customer_id, c.nameORDER BY total_spent DESC;
-- Find customers who never placed an orderSELECT c.*FROM customers cLEFT JOIN orders o ON c.customer_id = o.customer_idWHERE o.order_id IS NULL;13.3 RIGHT OUTER JOIN
Section titled β13.3 RIGHT OUTER JOINβRIGHT OUTER JOIN returns all rows from the right table and matched rows from the left table.
RIGHT JOIN Flow ========================================================================
βββββββββββββββββββ βββββββββββββββββββ β Table A β β Table B β β (customers) β β (orders) β β β β β β βββββββββββββββ β β βββββββββββββββ β β β id β name β β β β id β cust_id β β β βββββΌβββββββββ€ β β βββββΌββββββββββ€ β β β 1 β Alice β β β β 1 β 1 β β β β 2 β Bob β β β β 2 β 1 β β β β β β β β No β β 3 β 2 β β β β β β β match β β 4 β 5 β β β Orphan β βββββββββββββββ β β βββββββββββββββ β ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ β β βββββββββββββ¬ββββββββββββββββ β βΌ βββββββββββββββββββββββββββββββββββββββββββ β RIGHT JOIN Result β β (All from right + matches from left) β β β β cust_id β name β order_id β amount β β βββββββββΌβββββββββΌβββββββββββΌββββββββ β β 1 β Alice β 1 β 100.00 β β 1 β Alice β 2 β 50.00 β β 2 β Bob β 3 β 200.00 β β 5 β NULL β 4 β 75.00 β β No customer β β βββββββββββββββββββββββββββββββββββββββββββRIGHT JOIN Examples
Section titled βRIGHT JOIN Examplesβ-- Find all orders, including those without valid customersSELECT o.order_id, o.order_total, c.name as customer_nameFROM customers cRIGHT JOIN orders o ON c.customer_id = o.customer_id;13.4 FULL OUTER JOIN
Section titled β13.4 FULL OUTER JOINβFULL OUTER JOIN returns all rows when thereβs a match in either left or right table.
FULL JOIN Flow ========================================================================
βββββββββββββββββββ βββββββββββββββββββ β Table A β β Table B β β (customers) β β (orders) β β β β β β βββββββββββββββ β β βββββββββββββββ β β β id β name β β β β id β cust_id β β β βββββΌβββββββββ€ β β βββββΌββββββββββ€ β β β 1 β Alice β β β β 1 β 1 β β β β 2 β Bob β β β β 2 β 1 β β β β 3 β Charlieβ β β β 3 β 2 β β β β 4 β David β β β β 4 β 5 β β β βββββββββββββββ β β βββββββββββββββ β ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ β β βββββββββββββ¬ββββββββββββββββ β βΌ βββββββββββββββββββββββββββββββββββββββββββ β FULL OUTER JOIN Result β β (All rows from both tables) β β β β cust_id β name β order_id β amount β β βββββββββΌβββββββββΌβββββββββββΌββββββββ β β 1 β Alice β 1 β 100.00 β β 1 β Alice β 2 β 50.00 β β 2 β Bob β 3 β 200.00 β β 3 β Charlieβ NULL β NULL β β 4 β David β NULL β NULL β β 5 β NULL β 4 β 75.00 β β β βββββββββββββββββββββββββββββββββββββββββββFULL JOIN Examples
Section titled βFULL JOIN Examplesβ-- Find all customers and orders, showing relationshipsSELECT c.customer_id, c.name, o.order_id, o.order_totalFROM customers cFULL OUTER JOIN orders o ON c.customer_id = o.customer_idORDER BY c.customer_id, o.order_id;
-- Find orphaned orders and customers without orders in one querySELECT CASE WHEN c.customer_id IS NULL THEN 'Orphaned Order' WHEN o.order_id IS NULL THEN 'No Orders' END as data_issue, COALESCE(c.name, 'N/A') as customer_name, COALESCE(o.order_id::text, 'N/A') as order_idFROM customers cFULL OUTER JOIN orders o ON c.customer_id = o.customer_idWHERE c.customer_id IS NULL OR o.order_id IS NULL;13.5 Multiple JOINs
Section titled β13.5 Multiple JOINsβYou can chain multiple JOINs together to connect more than two tables.
-- Extended schema with multiple related tablesCREATE TABLE products ( product_id SERIAL PRIMARY KEY, product_name VARCHAR(100), category_id INTEGER);
CREATE TABLE order_items ( item_id SERIAL PRIMARY KEY, order_id INTEGER REFERENCES orders(order_id), product_id INTEGER REFERENCES products(product_id), quantity INTEGER, unit_price DECIMAL(10,2));
CREATE TABLE categories ( category_id SERIAL PRIMARY KEY, category_name VARCHAR(50));
-- Insert sample dataINSERT INTO categories (category_name) VALUES ('Electronics'), ('Clothing'), ('Books');
INSERT INTO products (product_name, category_id) VALUES ('Laptop', 1), ('Phone', 1), ('Shirt', 2), ('Book', 3);
INSERT INTO order_items (order_id, product_id, quantity, unit_price) VALUES (1, 1, 2, 999.99), (1, 3, 3, 29.99), (2, 2, 1, 599.99), (3, 4, 5, 19.99);
-- Multiple JOINs exampleSELECT c.name as customer_name, o.order_id, p.product_name, cat.category_name, oi.quantity, oi.unit_price, (oi.quantity * oi.unit_price) as line_totalFROM customers cINNER JOIN orders o ON c.customer_id = o.customer_idINNER JOIN order_items oi ON o.order_id = oi.order_idINNER JOIN products p ON oi.product_id = p.product_idINNER JOIN categories cat ON p.category_id = cat.category_idORDER BY o.order_id, p.product_name;13.6 Join Conditions
Section titled β13.6 Join ConditionsβUsing ON vs USING vs NATURAL JOIN
Section titled βUsing ON vs USING vs NATURAL JOINβ-- ON clause (most flexible)SELECT *FROM customers cINNER JOIN orders o ON c.customer_id = o.customer_id AND o.order_total > 100; -- Additional condition
-- USING clause (when columns have same name)SELECT *FROM customers cINNER JOIN orders o USING (customer_id);
-- NATURAL JOIN (automatic matching on same-named columns)SELECT *FROM customers cNATURAL JOIN orders o; -- Joins on customer_id automatically
-- Multiple conditionsSELECT *FROM table_a aLEFT JOIN table_b b ON a.id = b.a_id AND b.status = 'active' AND b.created_at > '2024-01-01';13.7 Practical Examples
Section titled β13.7 Practical ExamplesβE-commerce Analytics
Section titled βE-commerce Analyticsβ-- Comprehensive customer order analysisSELECT c.customer_id, c.name, c.email, COUNT(DISTINCT o.order_id) as total_orders, SUM(o.order_total) as lifetime_value, AVG(o.order_total) as avg_order_value, MIN(o.order_date) as first_order_date, MAX(o.order_date) as last_order_date, CASE WHEN COUNT(o.order_id) >= 10 THEN 'VIP' WHEN COUNT(o.order_id) >= 5 THEN 'Premium' WHEN COUNT(o.order_id) >= 1 THEN 'Regular' ELSE 'New' END as customer_tierFROM customers cLEFT JOIN orders o ON c.customer_id = o.customer_idGROUP BY c.customer_id, c.name, c.emailORDER BY lifetime_value DESC;13.8 Best Practices
Section titled β13.8 Best Practicesβ JOIN Best Practices ========================================================================
β DO: βββββββββββββββ β’ Use explicit JOIN syntax (not comma-separated FROM) β’ Always specify join conditions in ON clause β’ Use table aliases for readability β’ Consider join order for performance β’ Index columns used in JOIN conditions
β DON'T: βββββββββββββββ β’ Mix old-style and new-style joins β’ Forget to handle NULL values with COALESCE β’ Join on expressions that prevent index usage β’ Create Cartesian products by forgetting conditions β’ Join unnecessary tablesSummary
Section titled βSummaryβ| Join Type | Returns |
|---|---|
| INNER JOIN | Only matching rows from both tables |
| LEFT JOIN | All rows from left + matches from right |
| RIGHT JOIN | All rows from right + matches from left |
| FULL JOIN | All rows from both tables |
| CROSS JOIN | Cartesian product of both tables |