USING省掉“左表.字段 = 右表.字段”显式等值表达式,括号内仅写同名字段,多字段用逗号分隔,且SELECT *时自动去重同名字段,避免ambiguous错误。

USING 能简化 JOIN 语法,是因为它省掉了重复写表别名和等号逻辑的冗余,且在语义和结果集上做了自动规整——但只在严格满足同名、同类型、单字段(或多字段)等值连接时才成立。
USING 比 ON 少写什么?
核心是省掉「左表.字段 = 右表.字段」这种显式等值表达式。当你确认两个表的连接字段名完全一致(比如都是 user_id),USING(user_id) 就直接替代了 ON a.user_id = b.user_id。
-
USING括号里只写字段名,不带表名或别名 - 不能写表达式,比如
USING(UPPER(email))是非法的 - 多字段时用逗号分隔:
USING(user_id, tenant_id),比对应ON写法少一半字符且无歧义
SELECT * 时字段不重复,这是 ON 做不到的
这是最常被忽略的实际收益。USING 会让参与连接的字段在结果集中只出现一次;而 ON 下,如果没显式限定字段来源,SELECT * 会把左右表的同名字段都拖进来,导致后续引用报 Column 'xxx' in field list is ambiguous 错误。
- 合法:
SELECT * FROM orders o JOIN users u USING(user_id)→ 结果中只有 1 个user_id - 非法(或需改写):
SELECT * FROM orders o JOIN users u ON o.user_id = u.user_id→user_id出现两次,SELECT *可执行,但加WHERE user_id > 100就会报错 - 想用
ON达到同样效果,必须手动排除一个:SELECT o.*, u.name FROM ...,维护成本高
为什么有时候用了 USING 却报错?
常见失败不是语法错,而是隐性约束没被满足。MySQL 允许你写 USING(id),但只要两边字段类型不一致(比如一边是 INT,另一边是 BIGINT 或 VARCHAR),就会静默转成隐式转换,或直接报错(取决于 SQL mode)。
- 字段名必须**完全相同**:
user_id和uid不行,哪怕逻辑等价 - 数据类型需兼容:MySQL 可能容忍
TINYINT和SMALLINT,但CHAR(10)和TEXT通常不行 - 字符集/排序规则需一致:比如
utf8mb4_0900_as_cs和utf8mb4_unicode_ci在严格模式下可能拒绝连接 - 三表及以上链式连接时,中间表字段名若与末尾表不一致(如
t1.id → t2.owner_id → t3.user_id),USING无法跨跳,只能拆成多个ON
跨数据库迁移时,USING 是个隐藏雷区
它看着像标准 SQL,其实支持度极不均衡。MySQL 和 SQLite 支持完整 USING(含多字段、LEFT JOIN),PostgreSQL 仅支持单字段 USING,SQL Server 和 Oracle 完全不支持。
- 写完
USING(user_id, org_id)后切到 PostgreSQL?直接报错syntax error at or near "(" - Oracle 用户看到
USING,第一反应往往是 PL/SQL 的USING子句(绑定变量),和 JOIN 无关 - 团队共用一套 SQL 脚本做多环境部署时,建议把
USING当作“可选糖”,上线前统一转成ON更稳妥
真正省事的地方不在写的时候,而在读和维护的时候——字段自动去重、条件一目了然。但前提是,你清楚知道两张表的 schema 是对齐的,而且暂时不打算换数据库。

















