JOIN语句中的多个“ON”如何工作

时间:2013-11-04 00:31:30

标签: mysql sql

我正在阅读一个查询,在连接表时我通常不会在其他查询中看到这些查询。

SELECT 
    *
FROM table_1 
    RIGHT OUTER JOIN table_2 
    INNER JOIN table_3 
        ON table_2.some_id = table_3.some_id
    RIGHT OUTER JOIN table_4 
        ON table_3.some_id = table_4.some_id 
    LEFT OUTER JOIN table_5 
        ON table_4.some_id = table_5.some_id 
        ON table_1.some_id = table_4.some_id

请不要介意这些表格是如何加入的。我只想知道该查询是如何工作的?提前谢谢。

2 个答案:

答案 0 :(得分:3)

我认为SQL Server文档可以比MySQL更好地捕获正在发生的事情。 (Here是文档。)

正如劳伦斯观察到的那样,这是一个解析问题。您可以通过查看from语句的语法图来了解它是什么。有一个大多数人从未想过的递归参考(包括我)。联接表具有以下语法:

<joined_table> ::= 
{
    <table_source> <join_type> <table_source> ON <search_condition> 
    | <table_source> CROSS JOIN <table_source> 
    | left_table_source { CROSS | OUTER } APPLY right_table_source 
    | [ ( ] <joined_table> [ ) ] 
}

这里的关键是第一部分<table_source> <join_type> <table_source>。好吧,猜猜看,table_source可以是joined_table(以及其他一些东西)。这意味着语法:

A join B join C ON <condition1> ON <condition2>

符合上面的语法并解释为:

A join (B join C on <condition1>) ON <condition2>

即表达式B join C on <condition1>被视为“table_source”。

我的猜测是,如果SQL Server和MySQL都这样做,那么它可能是标准的一部分。但是,该标准比SQL Server的语法图更难理解。

答案 1 :(得分:2)

我认为这取决于评估右外连接的方式:

Select
  * 
from 
  a
    right outer join 
  b
    inner join
  c 
    on b.id = c.id 
    on a.id = b.id;

评估为

Select
  * 
from 
  a
    right outer join (
  b
    inner join
  c 
    on b.id = c.id 
  )
    on a.id = b.id;

混合左右外连接是疯狂的途径。

OP的查询似乎是由排除括号或派生表的愿望驱动的。它相当于:

Select
    a.id ida,
    b.id idb,
    c.id idc,
    d.id idd,
    e.id ide
From
    D
        left outer join
    A
        on d.id = a.id
        left outer join
    E
        on d.id = e.id
        left outer join (
    B
        inner join
    C
        on b.id = c.id
    ) 
        on d.id = b.id;

<强> Example SQLFiddle