想要了解我正在尝试剖析的视图的查询

时间:2018-03-05 18:43:37

标签: sql sql-server

我对我正在使用的一些查询感到困惑。

select *
from Table1
inner join Table2
  on Table1.id1 = Table2.id1
right outer join Table3
right outer join Table4
inner join Table5
  on Table4.id1 = Table5.id1
  on Table3.id1 = Table5.id2
  on Table1.id2 = Table5.id3

我试图让查询尽可能接近我正在使用的内容。

我不理解没有ON的连接,然后连接多个ON。 在表5加入之前,表3和表4是否实际上没有连接?

以下不起作用,因为Table5.id1和Table5.id2收到'多部分标识符'Table5.id_“无法绑定

select *
from Table1
inner join Table2
  on Table1.id1 = Table2.id1
right outer join Table3
  on Table3.id1 = Table5.id2
right outer join Table4
  on Table4.id1 = Table5.id1
inner join Table5
  on Table1.id2 = Table5.id3

此外,这个位确实处理,因为表5首先连接并解决了边界错误,但是我收到的记录比想要的多了27k

select *
from Table1
inner join Table2
  on Table1.id1 = Table2.id1
inner join Table5
  on Table1.id2 = Table5.id3
right outer join Table3
  on Table3.id1 = Table5.id2
right outer join Table4
  on Table4.id1 = Table5.id1

所以在这一点上很明显,原始查询是按照原因构建的,但我仍然不理解它背后的逻辑或实际发生的事情。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

这里有多个嵌套连接。在我解释之前,我会稍微重新格式化查询,以便更容易看到正在发生的事情。

select *
from Table1
inner join Table2 on Table1.id1 = Table2.id1
right outer join Table3 -- Join B
    right outer join Table4 -- Join A
        inner join Table5 on Table4.id1 = Table5.id1
    on Table3.id1 = Table5.id2 -- ON clause for Join A
on Table1.id2 = Table5.id3 -- ON clause for Join B

嵌套连接允许您将两个表连接在一起,然后将该结果连接到另一组记录。最初这听起来并不十分有用。这只是一次定期加入,对吧?均田。不同之处在于,只有当最内层连接成功时,它才会尝试将该行连接到外部表。如果你所做的只是使用内连接,这根本不是很有用。如果你正在混合内部和外部连接,那么它会变得更加有趣(稍后会详细介绍)。

我试图用散文和评论解释这个查询的内容,所以希望两者之间有意义。

首先,这里最里面的连接是表4和5之间的内部连接。这些表首先连接在一起。这将为您提供一个结果集,其中Table4中的每一行在表5中至少有一个匹配的行(根据on子句中存在的任何条件,在本例中为Table4.id1 = Table5.id1)。这隐式地过滤掉Table4和Table5中在其他表中没有匹配的任何行。

然后,该结果将正确连接到Table3(在Table3.id1 = Table5.id2上)。这意味着您将获得Table3中的所有记录以及Table4 / 5连接集中的相应匹配(如果存在)。

然后我们使用Table1(在Table3.id1 = Table5.id2上)对整个结果集进行右连接。这意味着我们最终将Table3中的所有内容加入Table4 / 5组合,然后加入表1/2组合。

最终结果集是Table3连接的所有内容,其中0行或多行与Table1和Table2匹配(如果Table1没有匹配的Table2记录,则不会加入Table3)。表4/5也是如此。我相信这是正确的(如果没有运行查询的能力,太过盯着它意味着我可能会把自己混淆,但基本的想法是正确的。)

那为什么这个疯狂的语法呢?替代品也是一种痛苦。您可以使用CTE或apply语句,这两种语句都是他们自己的乐趣(不一定很难,只是不是您的vanilla SQL。我尝试使用那些转换您的查询,我认为我得到了相当接近,然后我很困惑因为命名不好而我自己陷入了困境然后我放弃了。那么为什么呢?嗯,这意味着只有在前两个表中存在匹配项时,才能确保可以将两个表外连接到第三个表。也许一个更具体的例子会有所帮助吗?

假设您有4个表PersonOrderOrderItemOrderItemDiscount。您的任务是返回显示每个订单的结果集,并突出显示包含Figlewubbit的订单以及在其上使用折扣代码的订单。所以你写这个:

select *
from Person p
left join Order o on o.PersonId = p.PersonId
left join OrderItem oi on oi.OrderId = o.OrderId
                          and oi.ItemName = 'Figlewubbit'
left join OrderItemDiscount oid on oid.OrderItemId = oi.OrderItemId

另一种写作方式是:

select *
from Person p
left join Order o on o.PersonId = p.PersonId
left join OrderItem oi 
    inner join OrderItemDiscount oid on oid.OrderItemId = oi.OrderItemId
on oi.OrderId = o.OrderId
    and oi.ItemName = 'Figlewubbit'

此处的执行计划将会改变。 OrderItemOrderItemdDiscount会合在一起,然后该集会被送入Order左边的联接。每个OrderItemOrderItemdDiscount连接的行都被有效地视为其他连接的组合实体。你不会得到一个没有另一个。

(如果这个例子看起来很糟糕,我很抱歉。嵌套连接是一个奇怪的野兽。它们有它们的用途(我需要它们一次或两次)。但想出一个需要使用它们的简单例子是相当困难的它们是一种非常专业的工具,通常需要同样专业(和复杂)的要求才能保证它们的使用。我强烈建议先研究一下这些工具并先使用它们的简单版本。组合正确的连接和多个嵌套连接甚至让我头疼试图解析它。)

答案 1 :(得分:0)

实际上,首先连接表4和5,然后连接表3。这是执行计划:

enter image description here

相关问题