[MySQL, Oracle] FULL JOIN and Special Joins (SELF JOIN, NATURAL JOIN, SEMI JOIN, ANTI JOIN)
FULL (OUTER) JOIN
Provides a JOIN that includes all rows from both tables, filling unmatched rows with NULL values.
Features
- Union of the two tables
- Not supported in MySQL; must be implemented manually
(Supported in PostgreSQL, Oracle, SQL Server) - Rows existing only in one table have the corresponding columns set to
NULL
Example
Table data example
customer: (id=1, name=‘Dave’), (id=2, name=‘Jane’), (id=3, name=‘Lee’)
orders: (cust_id=1, order_date=‘2025–01–01’), (cust_id=2, order_date=‘2025–01–02’), (cust_id=4, order_date=‘2025–01–03’)
SELECT
c.id AS cust_id
, c.name
, o.order_date
FROM customer c
FULL OUTER JOIN orders o
ON c.id = o.cust_id;Result
1 | Dave | 2025–01–01
2 | Jane | 2025–01–02
3 | Lee | NULL
NULL | NULL | 2025–01–03
Implementing FULL JOIN in MySQL
SELECT
c.id AS cust_id
, c.name
, o.order_date
FROM customer c
LEFT JOIN orders o
ON c.id = o.cust_id
UNION
SELECT
c.id AS cust_id
, c.name
, o.order_date
FROM customer c
RIGHT JOIN orders o
ON c.id = o.cust_idHowever, note that the above method requires two
JOINoperations.
Performance Improvement Methods
While there is no method to significantly boost performance, improvements can be made as follows.
- Exclusive Union using Subqueries (Performance Optimization) — Performance-Focused
-- All left data + intersection
SELECT
c.id AS cust_id
, c.name
, o.order_date
FROM customer c
LEFT JOIN orders o
ON c.id = o.cust_id
UNION ALL -- Use UNION ALL without duplicate checks to reduce cost
-- Data present only in the right table (excluding intersection)
SELECT
o.cust_id
, o.name
, o.order_date
FROM customer c
RIGHT JOIN orders o
ON c.id = o.cust_id
WHERE c.id IS NULL; -- Excludes data already retrieved above2. Method using aggregate functions — Reduces computation when multiple tables are involved
SELECT
cust_id
, MAX(name) AS name
, MAX(order_date) AS order_date
FROM (
-- Prepare customer table data
SELECT id AS cust_id
, name
, NULL AS order_date
FROM customer
UNION ALL
-- Prepare orders table data
SELECT cust_id
, NULL AS name
, order_date
FROM orders)
AS combined
GROUP BY cust_id;SELF JOIN
Useful for hierarchical structures or self-referential data by joining with itself
Features
- Assigns different aliases to the table and connects via a common column
connects via a common column
SELECT e1.name
, e2.name
FROM employees e1
JOIN employees e2
ON e1.manager_id = e2.id;NATURAL JOIN
Automatically finds columns with the same name and data type in two tables for an equi JOIN
Get leedohyung28’s stories in your inbox
Join Medium for free to get updates from this writer.
Features
Connects without a separate ON condition if columns share the same name
SELECT *
FROM customers NATURAL JOIN cities;SEMI JOIN
Returns only rows from the left table that exist in the right table, without including the right table’s columns in the result.
Features
- Used to check if matching data exists rather than performing an actual join
- Uses
EXISTSorINoperators
-- Using EXISTS
SELECT *
FROM Customers c
WHERE EXISTS (
SELECT 1
FROM Orders o
WHERE o.customer_id = c.id
);-- Using IN
SELECT *
FROM Customers
WHERE id IN (
SELECT customer_id
FROM Orders
);vs. INNER JOIN
Example: If one customer places 100 orders
- INNER JOIN: The same customer name appears 100 times in the result. (Requires
DISTINCTto remove duplicates) - SEMI JOIN: The customer name appears only once in the result.
Purpose of SEMI JOIN
- Existence Check : When you need a list of subjects meeting specific conditions but don’t care about detailed records.
- Performance Optimization : Often faster than using
INNER JOIN+DISTINCT. - Data integrity check : When you want to filter only the dataset satisfying specific criteria.
ANTI JOIN
A JOIN technique that returns only data from the left table where no matching rows exist in the right table.
<=> SEMI JOIN
Features
- Extracting the difference set : Equivalent to finding the difference between two sets.
- Verifying Absence : Used when filtering targets lacking specific records.
- Duplicate removal effect
- Typically uses
NOT EXISTSorNOT INoperators.
-- Using NOT EXISTS
SELECT *
FROM Customers c
WHERE NOT EXISTS (
SELECT 1
FROM Orders o
WHERE o.customer_id = c.id
);-- Using NOT IN
SELECT *
FROM Customers
WHERE id NOT IN (
SELECT customer_id
FROM Orders
);-- LEFT JOIN + NULL check
SELECT c.*
FROM Customers c
LEFT JOIN Orders o
ON c.id = o.customer_id
WHERE o.customer_id IS NULL;Using
NOT INmay omit entire results if the right table containsNULLvalues.







