How to Use FULL JOIN in SQL
Use FULL JOIN when you need all rows from both tables, whether they match or not. This is ideal for audits, reconciliation, migration checks, and comparing two systems side by side.
What you’ll build or solve
You’ll learn how to use FULL JOIN in SQL to keep matched and unmatched rows from both tables. You’ll also know how to interpret NULL values on either side.
Learn SQL on Mimo
When this approach works best
This approach is the right choice when no rows from either table should be lost.
Common real-world scenarios include:
- CRM vs billing audits
- Product catalog reconciliation
- Old vs new system migration checks
- Inventory comparisons
- Employee roster merges
This is a bad idea when only one table needs guaranteed completeness. In that case, use LEFT JOIN or RIGHT JOIN.
Prerequisites
You only need:
- Two related SQL tables
- Basic join key knowledge
- Familiarity with
NULL
Step-by-step instructions
Step 1: Keep all rows from both tables with FULL JOIN
Use the shared key in the join condition.
SQL
SELECT crm.email, billing.email
FROM crm_users crm
FULL JOIN billing_users billing
ON crm.user_id = billing.user_id;
This returns:
- matched users from both tables
- CRM-only users
- billing-only users
Missing values on either side appear as NULL.
This makes FULL JOIN excellent for reconciliation work.
Use COALESCE() when you need one combined display value.
SQL
SELECT COALESCE(crm.email, billing.email) AS email
FROM crm_users crm
FULL JOIN billing_users billing
ON crm.user_id = billing.user_id;
What to look for:
- Keeps every row from both tables
- Unmatched sides become
NULL - Great for audits and comparisons
- Join on shared business keys
COALESCE()helps unify output
Examples you can copy
Inventory comparison
SQL
SELECT warehouse_a.sku, warehouse_b.sku
FROM warehouse_a
FULL JOIN warehouse_b
ON warehouse_a.sku = warehouse_b.sku;
User migration audit
SQL
SELECT legacy_users.email, new_users.email
FROM legacy_users
FULL JOIN new_users
ON legacy_users.user_id = new_users.user_id;
Team roster merge
SQL
SELECT hr.name, payroll.name
FROM hr
FULL JOIN payroll
ON hr.employee_id = payroll.employee_id;
Common mistakes and how to fix them
Mistake 1: Filtering unmatched rows away in WHERE
What the reader might do:
SQL
WHERE crm.email IS NOT NULL
Why it breaks: this removes billing-only rows.
Corrected approach:
Only filter when you intentionally want one side.
Mistake 2: Using the wrong join key
What the reader might do:
SQL
ON crm.email = billing.user_id
Why it breaks: unrelated columns create false matches.
Corrected approach:
Use the actual shared identifier.
Mistake 3: Using FULL JOIN when one table is primary
What the reader might do:
SQL
FULL JOIN profiles
Why it breaks: this adds unnecessary unmatched right-side rows.
Corrected approach:
Use LEFT JOIN when one side is primary.
Troubleshooting
If one-sided rows disappear, inspect the WHERE clause.
If too many rows appear, verify the join key.
If one combined column is needed, use COALESCE().
If your database does not support FULL JOIN, emulate it with UNION.
Quick recap
- Use
FULL JOINto keep all rows from both tables - Unmatched sides become
NULL - Great for audits and reconciliation
- Join on shared keys
- Use
COALESCE()for unified output
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot