검색과 인쇄가 가능한 SQL join 참고자료입니다: inner, left, right, full, anti, semi join, self join, ON 대 WHERE, LATERAL까지. 무료입니다.

Basic join types

9
SELECT * FROM a INNER JOIN b ON a.id = b.a_id;
Only rows with a match in BOTH tables
SELECT * FROM a LEFT JOIN b ON a.id = b.a_id;
All left rows, NULLs where no match
SELECT * FROM a RIGHT JOIN b ON a.id = b.a_id;
All right rows, NULLs where no match
SELECT * FROM a FULL OUTER JOIN b ON a.id = b.a_id;
All rows from both, NULLs if unmatched
JOIN = INNER JOIN
Plain JOIN defaults to INNER
LEFT OUTER JOIN = LEFT JOIN
The OUTER keyword is optional
LEFT JOIN ... UNION ... RIGHT JOIN ...
Emulate FULL JOIN in MySQL (none native)
ON a.id = b.a_id AND a.type = b.type
Compound (multi-column) join condition
ON a.qty BETWEEN p.min_qty AND p.max_qty
Non-equi join: match on a range

Anti-joins (no match)

8
LEFT JOIN b ON a.id = b.a_id WHERE b.a_id IS NULL
Left rows with NO match on the right
WHERE NOT EXISTS (SELECT 1 FROM b WHERE b.a_id = a.id)
Anti-join; safe with NULLs
WHERE a.id NOT IN (SELECT a_id FROM b)
One NULL in the list = empty result!
WHERE a.id NOT IN (SELECT a_id FROM b WHERE a_id IS NOT NULL)
NOT IN made NULL-safe
RIGHT JOIN a ... WHERE a.id IS NULL
Right rows with no match on the left
SELECT id FROM a EXCEPT SELECT a_id FROM b;
Set difference (Postgres, MySQL 8.0.31+)
users without orders = LEFT JOIN + IS NULL
The classic anti-join use case
Prefer NOT EXISTS over NOT IN
Same plan, none of the NULL traps

Semi-joins (has a match)

8
WHERE EXISTS (SELECT 1 FROM b WHERE b.a_id = a.id)
Left rows having a match; never duplicates
WHERE a.id IN (SELECT a_id FROM b)
Same intent; fine for short value lists
JOIN b ... GROUP BY a.id
JOIN duplicates 1-to-many; dedupe needed
SELECT DISTINCT a.* FROM a JOIN b ON ...
Semi-join via JOIN; EXISTS is cleaner
EXISTS stops at the first match
Often faster than joining everything
EXISTS (SELECT 1 ...) vs (SELECT * ...)
Selected columns are ignored; 1 is idiomatic
IN: uncorrelated / EXISTS: correlated
Optimizers usually rewrite them the same
users WITH orders = EXISTS subquery
The classic semi-join use case

Self joins

8
FROM emp e JOIN emp m ON e.manager_id = m.id
Each employee paired with their manager
FROM emp e LEFT JOIN emp m ON e.manager_id = m.id
Keeps top-level rows (manager is NULL)
SELECT e.name, m.name AS manager FROM ...
Aliases are REQUIRED to tell copies apart
ON a.id < b.id
Unique pairs: no self-match, no mirrors
ON a.id <> b.id
All ordered pairs except self-matches
ON b.day = a.day + INTERVAL 1 DAY
Adjacent rows (gaps and islands)
ON a.city = b.city AND a.id <> b.id
Other rows sharing the same value
WITH RECURSIVE tree AS (... UNION ALL ...)
Whole hierarchy: recursive CTE, not a join

Cross & multi-table joins

8
SELECT * FROM sizes CROSS JOIN colors;
Every combination: m x n rows, no ON
FROM sizes, colors
Implicit cross join; avoid this syntax
FROM users u JOIN orders o ON ... JOIN items i ON ...
Chain joins; each needs its own ON
JOIN dates d CROSS JOIN users u LEFT JOIN ...
Calendar x users grid, then fill data
u LEFT JOIN o ON ... LEFT JOIN i ON i.o_id = o.id
Keep LEFT down the chain to keep all users
u LEFT JOIN o ... INNER JOIN i ON i.o_id = o.id
INNER after LEFT drops the NULL rows!
FROM a JOIN (b LEFT JOIN c ON ...) ON ...
Parentheses control join grouping
Written order is logical, not execution order
The optimizer reorders inner joins freely

ON vs WHERE (the gotcha)

8
LEFT JOIN b ON a.id = b.a_id AND b.status = 1
Filters RIGHT side; all left rows kept
LEFT JOIN b ON a.id = b.a_id WHERE b.status = 1
NULL fails the test: LEFT becomes INNER!
WHERE b.a_id IS NULL OR b.status = 1
Keep unmatched rows despite a WHERE filter
LEFT JOIN b ON ... AND a.type = 'x'
Left-side filter in ON does NOT drop rows
WHERE a.type = 'x'
Filter the LEFT table in WHERE instead
INNER JOIN: ON and WHERE are equivalent
The trap only exists for outer joins
COALESCE(b.total, 0)
Replace outer-join NULLs with a default
COUNT(b.id) vs COUNT(*)
COUNT(col) skips NULLs: 0 for no match

USING, NATURAL & set ops

9
JOIN b USING (user_id)
Equi-join on a same-named column
USING outputs ONE shared column
ON keeps both a.user_id and b.user_id
NATURAL JOIN b
Auto-joins ALL same-named columns; fragile
Avoid NATURAL JOIN in production
A new column silently changes the join
SELECT ... UNION SELECT ...
Stack rows vertically, duplicates removed
UNION ALL
Keep duplicates; much faster than UNION
JOIN adds columns, UNION adds rows
Widen vs lengthen the result set
INTERSECT
Rows present in both result sets
UNION needs same column count and types
Names come from the first SELECT

LATERAL & performance

9
CROSS JOIN LATERAL (SELECT ... WHERE b.a_id = a.id LIMIT 3) t
Per-row subquery: top-N per group
LEFT JOIN LATERAL (...) t ON TRUE
Keep left rows whose subquery is empty
CROSS APPLY / OUTER APPLY
SQL Server spelling of LATERAL joins
LATERAL sees columns of preceding tables
A plain subquery in FROM cannot
CREATE INDEX idx ON orders (user_id);
Index the FK side of every frequent join
EXPLAIN SELECT ...;
Check join order, type, and index usage
Filter early: join the smallest set first
Less rows carried through each join
ON DATE(a.created_at) = b.day
Function on a column kills index use
Join on same-type, same-collation columns
Implicit casts also disable indexes

“:q”와 일치하는 항목이 없습니다.


SQL Join 치트시트 소개

이 SQL join 치트시트는 한 가지를 철저히 다룹니다: 테이블을 결합하는 모든 방법을 설명합니다. 8개 섹션에서 기본 join 종류, 일치하지 않는 행을 위한 anti-join, 일치하는 행을 위한 semi-join, self join, cross join과 다중 테이블 join, 고전적인 ON 대 WHERE 함정, USING, NATURAL과 집합 연산, 그리고 성능 참고 사항이 포함된 LATERAL join까지 다룹니다.

join은 SQL 결과가 조용히 잘못되기 쉬운 지점입니다: WHERE 절에서 필터링된 LEFT JOIN은 조용히 INNER JOIN이 되어버리고, NULL이 포함된 NOT IN은 아무것도 반환하지 않습니다. 이런 함정들이 올바른 대안 패턴과 함께 각각의 행으로 다뤄집니다.

이 그룹의 다른 치트시트와 마찬가지로 무료이며 클라이언트 측에서 동작합니다: 검색창으로 실시간으로 행을 필터링하고, 고정된 목차로 섹션을 이동하고, 클릭 한 번으로 문을 복사하고, 책상에서 참고할 수 있도록 페이지를 인쇄할 수 있습니다.

SQL Join 치트시트 사용 방법

  1. 시트를 열고 기본 join 종류부터 LATERAL & 성능까지 섹션을 검토하세요.
  2. LEFT JOIN, EXISTS, NOT IN 같은 키워드를 검색해 모든 행을 실시간으로 필터링하세요.
  3. 행이 너무 적게 반환되는 LEFT JOIN을 디버깅하기 전에 ON vs WHERE 섹션을 읽어보세요.
  4. 문이나 복사 아이콘을 클릭해 SQL을 클립보드에 복사하세요.
  5. 전체 join 참고자료를 종이로 보려면 인쇄를 사용하세요.

자주 묻는 질문

inner, left, right, full outer join과 함께 anti-join, semi-join, self join, cross join, 다중 테이블 join, USING과 NATURAL join, UNION 계열의 집합 연산, LATERAL join까지 다룹니다.

ON에 있는 조건은 outer join이 일치하지 않는 행을 유지하기 전에 결합할 테이블을 필터링합니다. 같은 조건이 WHERE에 있으면 그 이후에 실행되어 NULL 행을 제거하므로 LEFT JOIN이 INNER JOIN으로 바뀌어 버립니다. 이 시트에는 바로 이 내용을 다루는 섹션이 있습니다.

anti-join 섹션에서 LEFT JOIN … WHERE right.id IS NULL과 NOT EXISTS 패턴을 보여주고, 서브쿼리가 NULL을 반환할 수 있을 때 NOT IN이 왜 오작동하는지 설명합니다.

네. 표준 SQL 문법이므로 MySQL, PostgreSQL, SQL Server, SQLite에서 동작하며, 엔진별로 다른 몇 가지 사항은 해당 행에 직접 표시되어 있습니다.

네, 완전히 무료이며 로그인 없이 브라우저에서 실행됩니다.


인기 검색어
sql join 치트시트 sql join 종류 inner join vs left join sql anti join sql full outer join self join 예시 join에서 on vs where
도움이 필요하신가요?
이 도구에서 문제를 발견하셨나요? 저희 팀에 알려주세요.
문제 신고

이 무료 도구를 귀하의 웹사이트에 추가하세요: 아래 코드를 복사하여 붙여넣으세요.