单个INNER JOIN中多个ON子句的工作机制及多表关联逻辑疑问
详解SQL中JOIN的多条件逻辑与复杂语句分析
嘿,我来给你掰扯清楚这两个SQL问题,说得明明白白的:
一、单个INNER JOIN里的多条件匹配怎么工作?
首先得澄清一个常见误区:标准SQL里,单个INNER JOIN关键字后面只能跟一个ON子句,但你完全可以在这一个ON里用AND/OR组合多个匹配条件——这才是大家常说的“多条件JOIN”。举个例子:
SELECT * FROM user_info INNER JOIN order_list ON user_info.user_id = order_list.user_id AND order_list.order_status = 'completed'
这个语句的逻辑是:只有当用户ID匹配,并且订单状态是“已完成”时,这两行才会被关联起来。相当于在JOIN匹配的阶段就同时过滤掉不满足条件的行,和把条件丢到WHERE里的区别是,如果是LEFT JOIN的话,ON里的条件会影响JOIN的匹配结果(比如不满足条件的话,右表列会是NULL),而WHERE是过滤最终的结果集——不过这点在INNER JOIN里差异不大,只是逻辑顺序不同。
如果真的看到了多个独立的ON子句,那大概率是嵌套JOIN(也就是JOIN的优先级问题),比如把一个JOIN的结果当临时表,再和另一个表JOIN,这时候每个JOIN都会有自己的ON,但属于不同的JOIN层级,不是单个INNER JOIN的多个ON。
二、你给出的复杂JOIN语句,到底关联了哪些表?
先把你贴的SQL再放一遍,方便拆解:
select * from foo left join b on b.ID = foo.pID left join c inner join foo as f ON b.ID = f.pProject ON c.Name = f.Hostname
这里的核心是JOIN的优先级:INNER JOIN的优先级比LEFT JOIN高,所以这个语句的执行顺序是这样的:
- 第一步:先做
foo(主表)和b的LEFT JOIN,得到临时结果集T1——包含foo的所有行,以及匹配的b的行(不匹配的b列会是NULL)。 - 第二步:先执行隐含的嵌套逻辑(虽然没写括号,但优先级决定了):
c和foo as f做INNER JOIN,条件是b.ID = f.pProject——这里的b是来自T1的列,所以这个INNER JOIN其实是依赖T1里的b.ID值的,得到临时结果集T2,只有c和f匹配(且b.ID和f.pProject匹配)的行才会保留。 - 第三步:把T1和T2做
LEFT JOIN,条件是c.Name = f.Hostname,最终结果集包含T1的所有行,以及匹配的T2的行(不匹配的T2列是NULL)。
那回到你的问题:这个语句是不是把foo、b、c三个表都关联了?是的,但要注意foo被引用了两次(一次是主表,一次是别名f),不过物理表还是foo、b、c这三个。但这个写法可读性极差,建议加括号明确嵌套关系,改成这样:
select * from foo left join b on b.ID = foo.pID left join ( c inner join foo as f ON b.ID = f.pProject ) ON c.Name = f.Hostname
这样谁看了都能一眼明白嵌套逻辑,不会晕。
内容的提问来源于stack exchange,提问作者rmutalik
相关产品推荐
相关产品推荐

