加入后来提供的

时间:2011-03-04 16:05:08

标签: sql sql-server tsql join

我有以下格式的查询

select
    *
from
    Table1 t1
    inner join Table2 t2
    inner join Table3 t3 on t2.ID = t3.ID
    on t3.ID = t1.ID

我所知道的:

  1. 未提供最后on条件会导致错误。
  2. 此外,将第一个加入条件从on t2.ID = t3.ID更改为on t1.ID = t2.ID会导致错误t1.ID could not be bound
  3. 显然,上述例子是任意的,实际上可能不会产生实际有用的结果。但是,对后来提供on的内容的解释实际上是很好的。

    由于

    修改 我不是试图将问题改为有效的东西,而是在我提供它时理解MSSQL正在做什么。

4 个答案:

答案 0 :(得分:5)

这种编写连接子句的方法是在SQL Server中生成浓密查询计划的一种方法。查询优化器通常只考虑连接的一侧是基础对象(例如表或索引视图)的连接。

要创建一个计划,其中一个连接的结果直接连接到另一个连接的结果(一个浓密的计划),我们需要使用FORCE ORDER提示,并使用问题中显示的语法,或使用子查询(或公用表表达式)的等效结构:

-- Four sample tables
DECLARE @T1 TABLE (ID INT PRIMARY KEY);
DECLARE @T2 TABLE (ID INT PRIMARY KEY);
DECLARE @T3 TABLE (ID INT PRIMARY KEY);
DECLARE @T4 TABLE (ID INT PRIMARY KEY);

-- Some data
INSERT  @T1 VALUES (1),(2),(3),(4),(5),(6);
INSERT  @T2 VALUES (1),(2),(3),(4);
INSERT  @T3 VALUES (2),(4),(6);
INSERT  @T4 VALUES (1),(2),(3);

-- Bushy plan
SELECT  *
FROM    @T1
JOIN    @T2
        ON  [@T2].ID = [@T1].ID
JOIN    @T3
JOIN    @T4
        ON  [@T4].ID = [@T3].ID
        ON  [@T4].ID = [@T2].ID
OPTION  (FORCE ORDER);

-- Bushy plan, but note column aliases needed
SELECT  *
FROM    (
        SELECT  *
        FROM    @T1 AS T1
        JOIN    @T2 AS T2
                ON  T2.ID = T1.ID
        ) AS Q1 (ID, ID2)
JOIN    (
        SELECT  *
        FROM    @T3 AS T3
        JOIN    @T4 AS T4
                ON  T4.ID = T3.ID
        ) AS Q2 (ID3, ID4)
        ON Q2.ID4 = Q1.ID2
OPTION  (FORCE ORDER);

在'怪异'语法中,连接嵌套和ON clases不需要......但它确实使TSQL难以阅读,至少在我看来。在极少数情况下,一个浓密的计划总是产生比任何左深或右深的查询树更优化的计划,我可能会使用后一种语法。

答案 1 :(得分:3)

您可以使用您指定的格式(假设表格别名正确), if 使用括号。

Select ... -- never use Select *
From (Table1 As T1
    Join Table2 As T2
        On T2.ID = T1.ID)
    Join Table3 As T3
        On T3.ID = T1.ID

然而,对于equi-joins(内连接),它确实没有区别,如果你不使用括号,它会更容易阅读。但是,此格式对外连接非常有用。请看以下两个例子:

示例1

Select ...
From Table1 As T1
    Left Join Table2 As T2
        On T2.T1_ID = T1.ID
    Join Table3 As T3
        On T3.T2_ID = T2.ID

示例2

Select ...
From Table1 As T1
    Left Join (Table2 As T2
        Join Table3 As T3
            On T3.T2_ID = T2.ID)
        On T2.T1_ID = T1.ID

假设在这种情况下,T3.T2_ID是Table2的不可为空的外键。在Example1中,Inner Join to Table3将有效地过滤掉本来为null的行,因为Table1中不存在给定的T2.T2_ID。但是,在第二个示例中,Table2和Table3之间的连接是在处理之前的左连接之前完成的。因此,我们将从Table1和Table2获得相同的行:

示例3

Select ...
From Table1 As T1
    Left Join Table2 As T2
        On T2.T1_ID = T1.ID

答案 2 :(得分:2)

假设你的意思是t1而不是t,那么你的查询是:

select
    *
from
    Table1 t1
    inner join Table2 t2
    inner join Table3 t3 on t2.ID = t3.ID
    on t3.ID = t1.ID

...可以通过添加它不需要的括号来更清晰:

select
    *
from
    Table1 t1
      inner join 
        (Table2 t2 inner join Table3 t3 on t2.ID = t3.ID) on t3.ID = t1.ID

实际上,你明确地说“将t2加入t3,然后将t1加入到那里。”

这有帮助吗?

答案 3 :(得分:0)

首先关闭 - 你没有定义什么是

表1是别名t1 表2是别名t2 表3是别名t3

但没有简单的说明。

其次,你没有进行t1到t2的连接,而是从t1到t3,然后是t3到t2。那可行。如果t1和t2之间存在关系(t1.ID = t2.ID),那么“on”语句应直接跟随t2的内连接语句:

select
    *
from
    Table1 t1
    inner join Table3 t3 on t1.ID = t3.ID
    inner join Table2 t2 on t3.ID = t2.ID

更新(基于您的更新) t1.ID,t2.ID和t3.ID是否都是相同的数据类型?