APPLY 运算符 - 它如何决定哪些行是两组之间的匹配?
Posted
技术标签:
【中文标题】APPLY 运算符 - 它如何决定哪些行是两组之间的匹配?【英文标题】:APPLY operator - how does it decide which rows are a match between the two sets? 【发布时间】:2021-03-10 18:13:21 【问题描述】:使用 JOIN 时,很清楚是什么决定了行是否匹配,例如开启 a.SomeID1=b.SomeID1。因此,唯一返回的行将是别名 A 和 B 引用的表中存在匹配“SomeID1”的行。
我最初的想法是,在使用 APPLY 时,WHERE 子句通常放在右侧查询中,以提供与 JOIN 的 ON 子句类似的功能。
但是,我看到许多 SQL 查询在使用 APPLY 时在右侧查询中不包含 WHERE。那么这是否意味着结果行将只是两个表中行数的乘积?
使用 APPLY 时,什么逻辑决定左右查询匹配哪些行?
我尝试了很多博客文章、此处的答案,甚至 YouTube 视频,但没有一个解释让我“点击”。
【问题讨论】:
对数据集中的每一行应用“应用” 你见过这个吗? mssqltips.com/sqlservertip/1958/… 请记住,APPLY 是一个 SQL Server 扩展。你不会在大多数实现中找到它。 理解apply的关键在于它的不匹配,它的apply,它根据现有数据计算新数据,这与加入单独的数据完全不同。 在 APPLY 中,左表的每一行都与作为它的函数的右表交叉连接。 INNER JOIN ON 是 CROSS JOIN WHERE。 CROSS JOIN 是 INNER JOIN ON TRUE。 PS您只是要求另一个不理解的APPLY演示文稿,而我们不知道您不明白什么。阅读权威的介绍/教程/手册并询问 1 个特定研究的非重复问题,其中第一个问题。当您看到意外的示例/结果/输出时,请说出您的预期和原因,并参考引用的权威文档进行说明。 PS找一本教科书。数十人在线。 在考虑发布之前,请阅读手册并在谷歌上搜索任何错误消息以及您的问题/问题/目标的许多清晰、简洁和准确的措辞,包括和不包括您的特定名称/字符串/数字,“网站: ***.com 和标签;阅读许多答案。如果您发布问题,请使用一个短语作为标题。反映你的研究。请参阅How to Ask 和投票箭头鼠标悬停文本。 【参考方案1】:apply
运算符(在支持它的数据库中)实现了一种称为横向连接的join
。
对我来说,理解它的最佳方式是从相关子查询开始。例如:
select a.*,
(select count(*)
from b
where b.a_id = a.a_id
--------------^
) as b_count
from a;
子查询为a
中的每一行计算b
中匹配的行数。它是如何做到的?相关子句是将子查询映射到外部查询的条件。
Apply
的工作方式相同:
select a.*, b.b_count
from a outer apply
(select count(*) as b_count
from b
where b.a_id = a.a_id
------------^
) b;
换句话说,相关子句是您问题的答案。
横向连接和相关子查询有什么区别?有以下三个区别:
横向连接可以返回多行。 横向连接可以返回多于一列。 横向连接位于FROM
子句中,因此可以在查询中多次引用返回的列。
【讨论】:
【参考方案2】:进一步了解 Gordon 的出色回答:
APPLY
不需要相关(即它使用来自外部查询的列),关键是它是横向(它为 每个 行返回一个新结果集)。
所以从基本查询开始:
select c.*
from customer c;
示例结果:
Id | Name |
---|---|
1 | John |
2 | Jack |
这个想法是应用一个新的结果集。在这种情况下,我们只希望单个行(分组计数)应用于每个现有行。
注意where
相关性,我们使用外部引用
select c.*, o.Orders
from customer c
outer apply
(select count(*) as Orders
from [order] o
where o.c_id = c.id
) o;
Id | Name | Orders |
---|---|---|
1 | John | 2 |
2 | Jack | 0 |
但是,我们可以返回多个结果。事实上,我们可以返回任何我们喜欢的东西,并在结果上放置任意过滤器:
select c.*, t.*
from customer c
outer apply
(select 'Thing1' thing
union all
select 'Thing2'
where c.Name = 'Jack'
) t;
Id | Name | thing |
---|---|---|
1 | John | Thing1 |
1 | John | Thing2 |
2 | Jack | Thing1 |
请注意包含John
的行是如何根据过滤器加倍的。另请注意,union
的前半部分没有外部引用。
另请参阅 this answer 了解更多 APPLY
技巧。
【讨论】:
以上是关于APPLY 运算符 - 它如何决定哪些行是两组之间的匹配?的主要内容,如果未能解决你的问题,请参考以下文章
R:如何读取固定宽度的数据文件,其中数据连接成两组,堆叠在一个文件的顶部