这个没有子查询的“嵌套 JOIN”语法是什么?

What is this "nested JOIN" syntax without a subquery called?

提问人:Patrick Szalapski 提问时间:7/28/2023 最后编辑:Dale KPatrick Szalapski 更新时间:7/28/2023 访问量:147

问:

在 SQL Server (T-SQL) 中,我当然可以 JOIN 到子查询,但我刚刚了解到我也可以 JOIN 到不是子查询的嵌套 JOIN 表达式。例如:

SELECT *
FROM dbo.Customer c
JOIN ( /* note no SELECT */
    dbo.Table2 t2 
    JOIN dbo.Table3 t3 ON t3.t2Id = t2.Id
) ON c.t2Id = t2.Id  /* note no alias */
WHERE c.CustomerId = 1234;

这个“没有子查询的嵌套 JOIN”语法叫什么,我可以在 Microsoft 文档中找到它?在联接子查询的上下文中未提及它。

Server T-SQL 联接 嵌套

评论

3赞 jarlh 7/28/2023
FROM 子句子查询称为派生表
1赞 jarlh 7/28/2023
ANSI/ISO SQL 需要别名。
5赞 Stu 7/28/2023
你不需要 parehthesis afaik,也许这篇文章很有用 - “不要将此处括号的使用与派生表混淆。这不是一个派生表,而只是一种将一些表运算符分隔到它们自己的单位的方法,以便清楚起见。该语言实际上并不需要这些括号,但为了可读性,强烈建议使用它们。
3赞 jarlh 7/28/2023
是的,正如斯图指出的那样,这并不是一个真正的子问题。根据 developer.mimer.com/sql-2016-validator 的有效 SQL 标准语法。
3赞 T N 7/28/2023
不是派生表。不是子查询。不是临时表。它的作用是在逻辑上定义执行联接的顺序。它与内部连接几乎没有用处。它真正有用的地方是与外部连接一起使用时。一个示例用例可能是“所有剩余的订单都加入延期交货的产品”,但中间有一个联结表。在那里,你可能有.这允许在将订单详细信息和产品行馈送到 LEFT JOIN 之前进行合并。FROM Order O LEFT JOIN (OrderDetail OD JOIN Product P ON P.P_ID = OD.P_ID AND P.IsBackOrdered) ON OD.O_ID = O.O_ID

答:

0赞 Joel Coehoorn 7/28/2023 #1

括号是一个表表达式,它们意味着您肯定希望服务器在外部 JOIN 表达式之前完成嵌套的 JOIN 表达式。对于此查询,其中所有内容都是内部连接,这与以传统方式列出 JOIN 没有什么不同(只是要注意子句的编写方式):ON

SELECT *
FROM dbo.Customer c
JOIN dbo.Table2 t2 ON c.t2Id = t2.Id
JOIN dbo.Table3 t3 on t3.t2Id = t2.Id
WHERE c.CustomerId = 1234;

上面的查询将给出相同的结果,并且可以说更易于阅读和维护。

但是,可以使用括号内的表达式以比不带括号的查询更易于编写和理解的方式生成结果。OUTER JOIN

评论

2赞 The Impaler 7/28/2023
根据SQL标准,“表表达式”包括SELECT&FROM子句。
0赞 Dale K 7/28/2023
不,它不是,它是一个加入排序的东西 - 请参阅 Stu 在评论中发布的文章。
2赞 Charlieface 7/28/2023
请注意,括号是无关紧要的,它完全取决于子句的嵌套。另请参阅 stackoverflow.com/a/69427835/14868997JOIN ... JOIN ... ON ... ON...ON
1赞 Dale K 7/28/2023
解释一下当涉及左连接时会发生什么会更有用,就像发布的文章一样。
0赞 Martin Smith 7/29/2023
是的,从技术上讲,它不是“表表达式”,因为“表表达式是表示有效关系表的命名查询表达式”。 - 所以派生表、公共表表达式 (CTE)、视图和内联表值函数 - 但在 BNF 语法中,符号被调用,并在该上下文中用作<joined_table><table_source>
6赞 T N 7/28/2023 #2

不是派生表。不是子查询。不是临时表。它的作用是在逻辑上定义执行联接的顺序。它与内部连接几乎没有用处。它真正有用的地方是与外部连接一起使用时。

一个示例用例可能是“所有订单到延期交货的产品”,但中间有一个联结表。这可以编码为:left join

...
FROM Order O
LEFT JOIN (
    OrderDetail OD
    JOIN Product P
        ON P.ProductId= OD.ProductId
        AND P.IsBackOrdered = 1 -- Not proper design, but it's just an example
    )
    ON OD.OrderId = O.OrderId

这允许在将订单详细信息和产品行馈送到 LEFT JOIN 之前进行合并和筛选。

括号实际上是可选的,但我更喜欢包含它们以在一定程度上提高可读性(给读者一个提示,说明正在发生一些棘手的事情)。

但至于“它叫什么?我不认为它有名字。我将其视为分组联接无序联接。这几乎就像 HP-35 及其后继者时代的 HP 计算器的反向波兰符号 (RPN)。

评论

2赞 siggemannen 7/28/2023
很好的答案,@TN。我实际上更喜欢令人困惑的 select * from customer c LEFT JOIN Order o INNER JOIN OrderDetail od ON od.id = o.od ON o.id = c.id;
0赞 Patrick Szalapski 7/28/2023
知道Microsoft可以在哪里记录这一点吗?
1赞 Martin Smith 7/28/2023
在子句中。我也有一个HP RPN计算器。我记得当其他人要求借用计算器时,它引起了极大的困惑!FROM
1赞 Martin Smith 7/28/2023 #3

在 Microsoft 文档中的什么位置可以找到它?

FROM 子句中(正如 @mustaccio 在此跨站点欺骗中指出的那样)。

您的条款是FROM

FROM   dbo.Customer c
       JOIN ( dbo.Table2 t2
              JOIN dbo.Table3 t3
                ON t3.t2Id = t2.Id )
         ON c.t2Id = t2.Id 

请注意的语法是joined_table

<joined_table> ::=
{
    <table_source> <join_type> <table_source> ON <search_condition>
    ....
    | [ ( ] <joined_table> [ ) ]
}

所以以下是一个有效的<joined_table>

 dbo.Table2 t2
  JOIN dbo.Table3 t3
    ON t3.t2Id = t2.Id 

上面的语法还显示了可选的括号,可以应用于 a 以产生另一个有效的括号,所以这也是一个<joined_table><joined_table>

( dbo.Table2 t2
  JOIN dbo.Table3 t3
    ON t3.t2Id = t2.Id )

而且,正如该文档页面上的语法中进一步显示的那样,也是一个有效的.<joined_table><table_source>

所以你只是在做

SELECT *
FROM   dbo.Customer c
       JOIN <joined_table>
         ON c.t2Id = t2.Id 

并且,在某种程度上递归地,使用 a 作为 a 来产生进一步的 .<joined_table><table_source><joined_table>