在关系型数据库里,我们最熟悉的是通过主外键相等的“等值连接”,但业务里经常遇到按区间、按大小、按不等于来匹配两张表的情况,这就是非等值连接。它把连接条件从“列等于列”变成了“列大于列”“列 BETWEEN 低 AND 高”或者“列不等于列”,写在 JOIN 的 ON 子句中,由数据库引擎先生成两表的组合再按条件筛选。

一、非等值连接的基本写法
非等值连接的核心就是在 ON 后面使用比较运算符,而不是等号。最常见的场景是“打标签”或者“找相对关系”。比如有一张员工表 emp 和一张工资等级表 salgrade,后者用 losal 和 hisal 框定了每个等级的金额范围,我们想把每个员工的工资对应到等级,就可以用工资 BETWEEN 下限 AND 上限来连。
下面这段 SQL 展示了最基本的区间型非等值连接。它不会要求 emp.sal 等于某行 salgrade 的主键,而是判断落在哪个区间,因此同一张 salgrade 表可以被反复匹配,这是和等值连接语义上的最大不同。
SELECT
e.ename,
e.sal,
s.grade
FROM emp e
JOIN salgrade s
ON e.sal >= s.losal
AND e.sal <= s.hisal;
另一个常见需求是“自己比自己”,例如找出工资高于部门平均工资的员工。这种也可以用非等值连接配合聚合结果来做,而不一定非要用子查询。不过要注意,非等值连接容易产生较大的中间结果集,尤其是两边都是大表时,笛卡尔积膨胀会非常明显。
二、使用不等于号的非等值连接
不等于(<> 或 !=)也是一种非等值条件,常用于排除自身或者排除某些关联行。典型例子是员工表里找“入职比自己早且工资比自己低”的同事组合,用来做配对分析。此时 ON 里写的是日期小于、工资大于再加一个工号不等。
以下示例用 emp 表自连接,通过不等于工号来避免自己和自己比较,同时用范围判断筛选前后辈关系。这种写法比用 WHERE 里加条件更清晰,因为连接逻辑都收拢在 ON 里,后续如果改成外连接也只需要动 JOIN 类型。
SELECT
a.ename AS 前辈,
b.ename AS 后辈
FROM emp a
JOIN emp b
ON a.hiredate < b.hiredate
AND a.empno <> b.empno
AND a.sal > b.sal;
不等于号连接的风险在于它几乎无法利用常见的等值索引,多数情况下只能做全表扫描加过滤。如果业务允许,尽量把不等于转换成“小于某个值或大于某个值”的区间,或者配合其他等值条件缩小数据集,否则线上查询很容易超时。
三、范围判断连接与性能注意点
用 BETWEEN、>、< 做范围判断时,数据库优化器通常只能对其中一个边界使用索引,另一个边界仍要逐行比对。以订单表 orders 和汇率表 rates 为例,订单成交日要落到某个汇率生效区间内,就需要在 ON 里写 orders.trade_date >= rates.start_date 并且 <= rates.end_date。
下面代码演示了这种时间区间连接。如果 rates 表很小,数据库多半会选择把 rates 全量读入内存再遍历 orders;但如果 rates 也很大,就要考虑在 start_date、end_date 上建索引,或者把闭区间改成预计算好的日期映射表,用等值连接代替非等值连接来提升速度。
SELECT
o.order_id,
o.trade_date,
r.currency,
r.rate
FROM orders o
JOIN rates r
ON o.trade_date >= r.start_date
AND o.trade_date <= r.end_date;
从执行计划角度看,非等值连接往往出现 MERGE JOIN 或 NESTED LOOP 且无索引驱动的情况。写这类 SQL 时,建议先用小数据量 EXPLAIN 看是否产生了不合理的笛卡尔积,再把能等值化的条件(如币种相等)提前放到 ON 里,和非等值条件用 AND 组合,既保留业务逻辑又给优化器留出索引使用的空间。
四、与 WHERE 过滤的区别
有人会把非等值条件写在 WHERE 而不是 ON 里,在外连接场景下这两者结果完全不同。ON 里的条件决定“能不能连上”,连不上时右表字段为 NULL;WHERE 里的条件是在连完之后才过滤,可能把本该保留的 NULL 行删掉。所以只要是描述两表如何匹配的,都应放在 ON。
我们用左连接举例:想保留所有员工,哪怕没对应工资等级,等级条件就必须写在 ON。若错写到 WHERE,那些没有等级的人会因为 s.grade IS NULL 被过滤,业务含义就变了。下面是一个正确写法的片段,注意 ON 同时承载了区间与可选的等值条件。
SELECT
e.ename,
s.grade
FROM emp e
LEFT JOIN salgrade s
ON e.sal >= s.losal
AND e.sal <= s.hisal;
总结来说,非等值连接不是语法难点,而是建模思路的扩展。只要记住“匹配规则写在 ON,比较符号代替等号,注意数据集膨胀和索引利用”这三件事,就能在报表、区间映射、前后关系比对等场景里稳定地使用它。