所有工具
免费

可搜索、可打印的 SQL 连接参考——inner、left、right、full、anti 和 semi 连接、自连接、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 连接速查表

这份 SQL 连接速查表专注于一件事并做到透彻:解释表连接的每一种方式。八个章节涵盖了基本连接类型、用于查找没有匹配行的反连接、用于查找确实有匹配行的半连接、自连接、交叉连接和多表连接、经典的 ON 与 WHERE 陷阱、USING、NATURAL 和集合操作,以及 LATERAL 连接和性能说明。

连接是 SQL 结果悄悄出错的地方——在 WHERE 子句中过滤 LEFT JOIN 会静默地变成 INNER JOIN,而含有 NULL 的 NOT IN 会返回空结果。这些陷阱在这里各有专行,旁边是应该使用的正确写法。

与本系列的其他速查表一样,它免费且在客户端运行:使用搜索框实时过滤行,通过固定目录在章节间跳转,点击即可复制任何语句,还可以打印页面作为桌边参考。

如何使用 SQL 连接速查表

  1. 打开速查表,浏览各章节,从“基本连接类型”到“LATERAL 和性能”。
  2. 搜索关键词如 LEFT JOIN、EXISTS 或 NOT IN 以实时过滤每一行。
  3. 在调试返回行数过少的 LEFT JOIN 之前先阅读“ON 与 WHERE”章节。
  4. 点击语句或其复制图标,将 SQL 复制到剪贴板。
  5. 使用打印功能获取完整连接参考的纸质版。

常见问题

Inner、Left、Right 和 Full Outer Join,还有反连接、半连接、自连接、交叉连接、多表连接、USING 和 NATURAL Join、UNION 系列的集合操作,以及 LATERAL Join。

ON 中的条件在外连接保留未匹配行之前过滤被连接的表;WHERE 中的相同条件在之后运行并丢弃 NULL 行,从而将 LEFT JOIN 变成 INNER JOIN。速查表有专门的章节讲解这一点。

反连接章节展示了 LEFT JOIN ... WHERE right.id IS NULL 和 NOT EXISTS 写法,并解释了当子查询可能返回 NULL 时 NOT IN 为什么会出问题。

是的。语法是标准 SQL,在 MySQL、PostgreSQL、SQL Server 和 SQLite 中均可使用,少量引擎特定的说明直接标注在行上。

是的,完全免费,在浏览器中运行,无需登录。


热门搜索
sql 连接速查表 sql 连接类型 inner join 和 left join 的区别 sql 反连接 sql full outer join 自连接示例 连接中 on 和 where 的区别
需要帮助?
使用此工具时遇到问题?请告诉我们的团队。
报告问题

将此免费工具添加到你自己的网站 — 复制并粘贴下面的代码。