使用方法
选择连接类型后点击“计算连接”。员工表与部门表都以逗号分列,首行字段名必须分别保持 id,name,dept_id 和 id,dept;无部门的员工写 NULL。两个文本框已经由服务端直出示例,修改后可按 Ctrl+Enter 或 Cmd+Enter 重算;右表部门条件输入框按回车也会触发。错误提示会指出是表头、字段数、编号、空名称还是重复主键,不会把不同格式问题合并成同一句话。
“当前连接结果”按照所选语义实算,超过六行时先展示六行;“全部连接逐行对照”把各类结果合并为长表,默认展示十二行,点击“加载更多”后展开。两个表都可复制为 TSV,CSV 导出会写入带 BOM 的完整对照表,便于在表格软件中保留中文列名。恢复示例会重新放入四名员工和三个部门,而不是复用已经编辑过的数据。
建议先保持默认数据依次切换连接,再只改一个条件观察差异。例如把连接类型从 LEFT 改成 RIGHT 时,保留侧从员工变成部门;把研发条件从 WHERE 移到 ON 时,保留侧没有变化,但条件的生效阶段改变。每次只变动一个要素,结果表中的新增行、消失行和 NULL 补位就能对应到具体语义。
能解决什么
JOIN 的难点通常不在关键字拼写,而在“哪一边必须保留”和“条件在哪个阶段生效”。INNER 只留下双方匹配行;LEFT 必须保住每个员工;RIGHT 必须保住每个部门;FULL 同时保留两侧未匹配行;CROSS 不读取关联键,直接形成组合。页面把抽象定义换成具体行,因此能直接看到王五的空部门、赵六的无对应部门以及财务部门的无员工状态。
本页也覆盖两个常被混写的需求:LEFT JOIN ... WHERE d.dept IS NULL 是找“左表有、右表没有”的差集;LEFT JOIN ... WHERE d.dept='研发' 则会在连接完成后删除右侧为 NULL 的行,使外连接失去保留效果。工具目录曾使用“SQLJoinsVisual速查表”这一名称,本页用可编辑数据和逐行结果表达其真实用途。
原理与变量
示例 EMP 有四行:张三的 dept_id=10,李四为 20,王五为 NULL,赵六为 30。DEPT 有三行:10 是研发,20 是市场,40 是财务。匹配谓词是 e.dept_id=d.id。张三与李四命中;王五没有连接键;赵六的键在部门表中不存在;财务则没有员工引用。
在数组实现中,INNER 遍历员工并只输出匹配部门;LEFT 对每名员工查找部门,找不到就用 NULL 补右列;RIGHT 反过来以部门为保留侧;FULL 先取得 LEFT,再附加右表未匹配行;CROSS 对每名员工遍历每个部门。差集从 LEFT 结果中过滤部门对象为空的行。这个实现按行计算,不读取正文里的预设行数,因此编辑示例后,结果行和状态统计会一起变化。
ON 与 WHERE 的执行位置决定保留语义。把 d.dept='研发' 放在 ON 中,含义是“只让研发部门参与匹配,但仍保留全部 EMP”;放在 WHERE 中,含义是“连接后只保留部门值为研发的结果”。后者会把外连接产生的 NULL 一并过滤。FULL 的 MySQL 写法采用 LEFT 与 RIGHT 的 UNION 组合,因为 MySQL 没有原生 FULL OUTER JOIN。
还要区分“参与匹配的键”和“最终选择的列”。连接条件使用部门编号,SELECT 却可以只显示员工与部门名称;如果只看两列名称,王五和赵六都会呈现 NULL,无法判断前者是空键、后者是悬空键。因此交互结果保留 EMP.dept_id 与 DEPT.id 两列,让匹配失败的来源可见。这正是排查外键缺失与主数据缺口时需要的信息。
完整示例
使用默认数据时,INNER 产生两行:张三对应研发,李四对应市场。LEFT 产生四行,除两条匹配外,王五与赵六的部门都显示 NULL。RIGHT 产生三行,前两条仍是张三与李四,另有一条员工为 NULL、部门为财务。FULL 产生五行,等于 LEFT 的四行再加右表未匹配的财务一行。CROSS 产生十二行,因为四名员工分别与三个部门组合。
选择“LEFT JOIN + IS NULL”得到两行:王五与赵六,正好是 EMP 中没有对应 DEPT 的记录。选择 WHERE 陷阱并保持条件为研发,只剩张三与研发一行;王五和赵六并不是被连接过程丢掉,而是在 WHERE 阶段因为右侧 NULL 不等于研发而被删除。切换到 ON 条件后仍保留四行:张三匹配研发,其余员工的右侧均补 NULL。
这些数量满足两条核对关系:INNER 的两行加 LEFT 差集的两行,等于 EMP 的四行;FULL 的五行等于 LEFT 的四行加右表未匹配的一行。如果实现得出不同数量,应先检查 NULL 是否被当作字符串连接、未匹配行是否重复加入,以及 RIGHT 或 FULL 是否错误地按左表键去重。
对照表
| 连接或条件 | 默认结果行数 | 必须出现的未匹配行 |
|---|---|---|
| INNER JOIN | 2 | 无 |
| LEFT JOIN | 4 | 王五 | NULL;赵六 | NULL |
| RIGHT JOIN | 3 | NULL | 财务 |
| FULL OUTER JOIN | 5 | 两名未匹配员工与财务部门 |
| CROSS JOIN | 12 | 不区分匹配,形成 4 × 3 组合 |
| LEFT JOIN + IS NULL | 2 | 王五 | NULL;赵六 | NULL |
| WHERE 部门为研发 | 1 | 未匹配员工被过滤 |
| ON 部门为研发 | 4 | 其余员工仍保留 |
表中的 NULL 表示对应侧没有行,不是员工或部门字段里真的保存了文本“NULL”。逐行结果把 EMP 的部门键与 DEPT 的主键分开显示,能辨认赵六的 30 是“有键但找不到部门”,而王五是“连接键本身为空”。
结果边界与舍入
JOIN 是集合与行匹配运算,没有小数舍入。边界主要来自 NULL、重复键和多对多关系。SQL 中 NULL 不等于任何值,也不等于另一个 NULL,所以普通等值条件不会让两个 NULL 自动匹配。本页把输入文本里的大写 NULL 解析成空值;部门编号必须是整数,员工的部门编号可以为空。部门主键重复时页面会报错,避免把本应唯一的示例维表悄悄扩成一对多。
如果真实数据库允许部门表同一编号出现多行,一名员工会匹配出多行,INNER 与 LEFT 的行数都可能超过员工数;CROSS 的数量则始终是两表行数的乘积。UNION 模拟 FULL 时还要理解 UNION 会去重,若业务需要保留完全相同的重复行,应设计可辨识的主键并审查 UNION ALL 的反重复条件,不能机械替换。
条件引用右表字段时,WHERE 对 NULL 的过滤是三值逻辑带来的结果。要保留左表,应把只限制匹配资格的右表条件放到 ON;只有确实要在连接后筛掉行时才放 WHERE。工具展示的是连接语义与结果形状,不连接数据库,也不执行用户提供的 SQL 文本。
真实查询还可能因为 SELECT 列不足而产生“看似重复”的行。连接本身不会替用户判断两行是否属于同一业务对象,DISTINCT 也不应拿来掩盖错误关联。先核对连接键的唯一性、允许为空的范围和保留侧,再决定是否去重,才能解释结果数量为何变化。页面用唯一部门编号固定这一前提,让每种默认行数都能从输入逐条复算。
常见问题
LEFT JOIN 为什么会退化成 INNER?
连接先生成右侧为 NULL 的未匹配行,随后 WHERE 要求右表字段等于研发,这些 NULL 行无法满足条件而被删除,最终只剩能匹配且符合条件的行。
把部门条件放进 ON 有什么不同?
ON 只决定右表哪些行能够匹配,不取消 LEFT 对左表的保留承诺。默认数据下,研发条件写进 ON 后仍有四行,其余员工右侧补 NULL。
如何找没有部门的员工?
使用 LEFT JOIN 后在 WHERE 中判断右表主键或部门字段 IS NULL。默认数据会得到王五和赵六两行,其中一个连接键为空,一个连接键没有对应记录。
MySQL 怎么写 FULL OUTER JOIN?
MySQL 不支持这个关键字。常见模拟是 LEFT JOIN 与 RIGHT JOIN 通过 UNION 合并;需要保留重复行时,还要结合主键和未匹配条件审查去重策略。
RIGHT JOIN 能否改写成 LEFT JOIN?
可以交换两张表的位置并改成 LEFT JOIN。改写后要同步调整 SELECT 列和别名,确保原本需要完整保留的部门表仍处在左侧。
CROSS JOIN 为什么有十二行?
它不使用部门键匹配,而是让四名员工分别组合三个部门,所以得到十二行。编辑任一表的行数后,结果会按两表行数的乘积变化。
王五与赵六的 NULL 有何区别?
结果里都显示部门为空,但原因不同:王五的 EMP.dept_id 本身是 NULL;赵六保存了 30,只是 DEPT 中没有编号 30。
导出表为什么带 BOM?
CSV 文件开头加入 BOM,便于常见表格软件按 UTF 编码识别中文。复制 TSV 不加 BOM,可直接粘贴到编辑器或电子表格。
相关工具
连接结果确认后,可以继续格式化 SQL、把 INSERT 数据转成 JSON、检查 JSONPath,或处理 SQL 字符串转义: