sql - 想要了解我正在尝试剖析的 View 的查询

标签 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 的连接。 表 3 和表 4 是否在联接表 5 之后才真正联接?

以下内容不起作用,因为 Table5.id1 和 Table5.id2 收到“无法绑定(bind)多部分标识符“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

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

任何帮助将不胜感激。

最佳答案

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

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 中的每一行在 Table5 中至少有一个匹配行(根据 on 子句中存在的任何条件,在本例中为 Table4.id1 = Table5.id1) .这会隐式地过滤掉 Table4 和 Table5 中在另一个表中没有匹配项的任何行。

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

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

最终结果集是 Table3 中的所有内容以及与 Table1 和 Table2 匹配的 0 行或更多行(如果 Table1 没有匹配的 Table2 记录,则两者都不会连接到 Table3)。与表 4/5 相同。我相信这是正确的(在没有能力运行查询的情况下过多地盯着这个意味着我可能把自己弄糊涂了,但基本的想法是正确的)。

那么为什么要使用这种疯狂的语法呢?替代品也是一种痛苦。您可以使用 CTE 或 apply 语句,它们都有自己的乐趣(不一定很难,只是不是您的普通 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 联接行都被有效地视为其他联接的组合实体。缺一不可。

(如果这个例子看起来做作,我深表歉意。嵌套连接是一种奇怪的野兽。它们有它们的用途(我曾经需要它们一两次)。但是想出一个需要它们的简单例子是相当困难的。它们是一个非常专业的工具,通常需要同样专业(和复杂)的要求才能保证使用它们。我强烈建议对此进行更多研究并首先使用它们的简单版本。组合右连接和多个嵌套连接甚至让我头疼尝试解析它。)

关于sql - 想要了解我正在尝试剖析的 View 的查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49117389/

相关文章:

重叠时间框架的 SQL 解决方案

c# - 错误 : There is already an open DataReader associated with this Command which must be closed first

python - 使用 pyodbc 读取 SSMS 输出消息

sql-server - SQL 服务器错误?

sql - MS SQL Server 的 "between"是否包含范围边界?

MySQL:如何使用别名构造新字段?

sql - Amazon Redshift 中的 WHERE EXISTS 与 IN

php - 如何在 Laravel 之外使用 Eloquent 时创建 SQL View

sql-server - 为什么 sp_rename 不适用于 CHECK 约束?

mysql - 使用 pivot 命令时出现动态 SQL 错误