什么时候应该在内部联接上使用交叉应用?
使用CROSS APPLY的主要目的是什么?
我已经读过(模糊地通过Internet上的帖子),如果您正在分区,则在选择大型数据集时, cross apply
会更有效。 (想起分页)
我也知道, CROSS APPLY
不需要UDF作为右表。
在大多数INNER JOIN
查询(一对多关系)中,我可以重写它们以使用CROSS APPLY
,但是它们总是给我等效的执行计划。
在CROSS APPLY
在INNER JOIN
也能正常工作的情况下, CROSS APPLY
时,谁能给我一个很好的例子?
编辑:
这是一个简单的示例,其中执行计划完全相同。 (向我展示它们的不同之处和cross apply
的更快/更有效的地方)
create table Company (companyId int identity(1,1)
, companyName varchar(100)
, zipcode varchar(10)
, constraint PK_Company primary key (companyId)
)
GOcreate table Person (personId int identity(1,1)
, personName varchar(100)
, companyId int
, constraint FK_Person_CompanyId foreign key (companyId) references dbo.Company(companyId)
, constraint PK_Person primary key (personId)
)
GOinsert Company
select 'ABC Company', '19808' union
select 'XYZ Company', '08534' union
select '123 Company', '10016'insert Person
select 'Alan', 1 union
select 'Bobby', 1 union
select 'Chris', 1 union
select 'Xavier', 2 union
select 'Yoshi', 2 union
select 'Zambrano', 2 union
select 'Player 1', 3 union
select 'Player 2', 3 union
select 'Player 3', 3 /* using CROSS APPLY */
select *
from Person p
cross apply (select *from Company cwhere p.companyid = c.companyId
) Czip/* the equivalent query using INNER JOIN */
select *
from Person p
inner join Company c on p.companyid = c.companyId
#1楼
在我看来,CROSS APPLY在处理复杂/嵌套查询中的计算字段时可以填补一定的空白,并使它们更简单易读。
举个简单的例子:您有一个DoB,并且想要显示多个与年龄相关的字段,这些字段也将依赖于其他数据源(例如,就业),例如Age,AgeGroup,AgeAtHiring,MinimumRetirementDate等,供最终用户应用程序使用(例如,Excel PivotTables)。
选项是有限的,很少是优雅的:
JOIN子查询不能基于父查询中的数据在数据集中引入新值(它必须独立存在)。
UDF整洁,但速度较慢,因为它们倾向于阻止并行操作。 作为一个单独的实体可以是一件好事(更少的代码)也可以是一件坏事(代码在哪里)。
连接表。 有时它们可以工作,但是很快您就可以与大量UNION一起加入子查询。 大混乱。
假设您的计算不需要在主查询过程中获取的数据,则可以创建另一个视图。
中间表。 是的...通常可以正常工作,并且通常是一个不错的选择,因为它们可以被索引并且速度很快,但是由于UPDATE语句不平行并且不允许级联公式(重用结果)来更新内部的多个字段,因此性能也会下降相同的声明。 有时,您只喜欢一次性完成任务。
嵌套查询。 是的,您可以随时在整个查询上加上括号并将其用作子查询,在子查询上您可以操作源数据和计算字段。 但是您只能在丑陋之前做很多事情。 十分难看。
重复代码。 3个长(CASE ... ELSE ... END)语句的最大值是多少? 那将是可读的!
- 告诉您的客户自己计算该死的事情。
我错过了什么? 可能吧,随时发表评论。 但是,在这种情况下,CROSS APPLY就像天赐之物:您只需添加一个简单的CROSS APPLY (select tbl.value + 1 as someFormula) as crossTbl
和CROSS APPLY (select tbl.value + 1 as someFormula) as crossTbl
! 现在,您的新字段几乎可以像源数据中一直存在的那样准备好使用。
通过CROSS APPLY引入的值可以...
- 用于创建一个或多个计算字段,而不会增加性能,复杂性或可读性
- 像JOIN一样,几个后续的CROSS APPLY语句可以引用自己:
CROSS APPLY (select crossTbl.someFormula + 1 as someMoreFormula) as crossTbl2
- 您可以在随后的JOIN条件中使用CROSS APPLY引入的值
- 作为奖励,还有表值函数方面
ang,他们无能为力!
#2楼
在CROSS APPLY在INNER JOIN也能正常工作的情况下,CROSS APPLY有所作为时,谁能给我一个很好的例子?
有关性能比较的详细信息,请参阅我博客中的文章:
INNER JOIN
与CROSS APPLY
在没有简单的JOIN
条件的情况下, CROSS APPLY
效果更好。
这个从t2
为t1
每个记录选择3
最后记录:
SELECT t1.*, t2o.*
FROM t1
CROSS APPLY(SELECT TOP 3 *FROM t2WHERE t2.t1_id = t1.idORDER BYt2.rank DESC) t2o
在INNER JOIN
条件下不容易配制。
您可能可以使用CTE
和window函数执行类似的操作:
WITH t2o AS(SELECT t2.*, ROW_NUMBER() OVER (PARTITION BY t1_id ORDER BY rank) AS rnFROM t2)
SELECT t1.*, t2o.*
FROM t1
INNER JOINt2o
ON t2o.t1_id = t1.idAND t2o.rn <= 3
,但可读性较低,效率可能较低。
更新:
刚刚检查。
master
是一个包含约20,000,000
条记录的表,其id
为PRIMARY KEY
。
该查询:
WITH q AS(SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rnFROM master),t AS (SELECT 1 AS idUNION ALLSELECT 2)
SELECT *
FROM t
JOIN q
ON q.rn <= t.id
运行了将近30
秒,而这一个:
WITH t AS (SELECT 1 AS idUNION ALLSELECT 2)
SELECT *
FROM t
CROSS APPLY(SELECT TOP (t.id) m.*FROM master mORDER BYid) q
是即时的。
#3楼
我想应该是可读性;)
对于那些要告诉他们正在使用UDF的人来说,CROSS APPLY在某种程度上将是唯一的,它将应用于左侧表格的每一行。
当然,还有其他一些限制,那就是使用CROSS APPLY比使用其他好友在上面发布的JOIN更好。
#4楼
交叉应用同样适用于XML字段。 如果要与其他字段一起选择节点值。
例如,如果您有一个包含一些xml的表
<root> <subnode1> <some_node value="1" /> <some_node value="2" /> <some_node value="3" /> <some_node value="4" /> </subnode1> </root>
使用查询
SELECTid as [xt_id],xmlfield.value('(/root/@attribute)[1]', 'varchar(50)') root_attribute_value,node_attribute_value = [some_node].value('@value', 'int'),lt.lt_name
FROM dbo.table_with_xml xt
CROSS APPLY xmlfield.nodes('/root/subnode1/some_node') as g ([some_node])
LEFT OUTER JOIN dbo.lookup_table lt
ON [some_node].value('@value', 'int') = lt.lt_id
将返回结果
xt_id root_attribute_value node_attribute_value lt_name
----------------------------------------------------------------------
1 test1 1 Benefits
1 test1 4 FINRPTCOMPANY
#5楼
交叉应用可用于替换需要子查询列的子查询
子查询
select * from person p where
p.companyId in(select c.companyId from company c where c.companyname like '%yyy%')
在这里,我将无法选择公司表的列,因此,使用交叉应用
select P.*,T.CompanyName
from Person p
cross apply (select *from Company Cwhere p.companyid = c.companyId and c.CompanyName like '%yyy%'
) T
#6楼
考虑您有两个表。
主表
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
详情表
x------x--------------------x-------x
| Id | PERIOD | QTY |
x------x--------------------x-------x
| 1 | 2014-01-13 | 10 |
| 1 | 2014-01-11 | 15 |
| 1 | 2014-01-12 | 20 |
| 2 | 2014-01-06 | 30 |
| 2 | 2014-01-08 | 40 |
x------x--------------------x-------x
在很多情况下,我们需要用CROSS APPLY
替换INNER JOIN
。
1.根据TOP n
结果联接两个表
考虑是否需要从Master
选择Id
和Name
,并从Details table
为每个Id
选择最后两个日期。
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
INNER JOIN
(SELECT TOP 2 ID, PERIOD,QTY FROM DETAILS D ORDER BY CAST(PERIOD AS DATE)DESC
)D
ON M.ID=D.ID
- SQL字段
上面的查询生成以下结果。
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
x------x---------x--------------x-------x
看到,它生成了最后两个日期和最后两个日期的Id
,然后仅在Id
的外部查询中加入了这些记录,这是错误的。 为此,我们需要使用CROSS APPLY
。
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
CROSS APPLY
(SELECT TOP 2 ID, PERIOD,QTY FROM DETAILS D WHERE M.ID=D.IDORDER BY CAST(PERIOD AS DATE)DESC
)D
- SQL字段
并形成以下结果。
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-08 | 40 |
| 2 | B | 2014-01-06 | 30 |
x------x---------x--------------x-------x
运作方式如下。 CROSS APPLY
内部的查询可以引用外部表,而INNER JOIN
不能执行此操作(它会引发编译错误)。 当找到最后两个日期时,将在CROSS APPLY
WHERE M.ID=D.ID
,即WHERE M.ID=D.ID
2.当我们需要使用函数的INNER JOIN
功能时。
当我们需要从Master
表和function
获取结果时,可以将CROSS APPLY
替换为INNER JOIN
。
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C
这是功能
CREATE FUNCTION FnGetQty
( @Id INT
)
RETURNS TABLE
AS
RETURN
(SELECT ID,PERIOD,QTY FROM DETAILSWHERE ID=@Id
)
- SQL字段
产生了以下结果
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-11 | 15 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-06 | 30 |
| 2 | B | 2014-01-08 | 40 |
x------x---------x--------------x-------x
交叉申请的其他优势
APPLY
可以用作UNPIVOT
的替代品。 可以在此处使用“ CROSS APPLY
或“ OUTER APPLY
,它们可以互换。
考虑您具有下表(名为MYTABLE
)。
x------x-------------x--------------x
| Id | FROMDATE | TODATE |
x------x-------------x--------------x
| 1 | 2014-01-11 | 2014-01-13 |
| 1 | 2014-02-23 | 2014-02-27 |
| 2 | 2014-05-06 | 2014-05-30 |
| 3 | NULL | NULL |
x------x-------------x--------------x
查询如下。
SELECT DISTINCT ID,DATES
FROM MYTABLE
CROSS APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
- SQL字段
为您带来结果
x------x-------------x| Id | DATES |x------x-------------x| 1 | 2014-01-11 || 1 | 2014-01-13 || 1 | 2014-02-23 || 1 | 2014-02-27 || 2 | 2014-05-06 || 2 | 2014-05-30 | | 3 | NULL | x------x-------------x
#7楼
这也许是一个古老的问题,但是我仍然喜欢CROSS APPLY的强大功能,它可以简化逻辑的重用并提供结果的“链接”机制。
我在下面提供了一个SQL Fiddle,它显示了一个简单的示例,说明如何使用CROSS APPLY对数据集执行复杂的逻辑操作而不会造成任何混乱。 从这里不难推断出更复杂的计算。
http://sqlfiddle.com/#!3/23862/2
#8楼
这是一篇说明所有内容的文章,它们的性能差异和与JOINS的用法不同。
SQL Server通过联接进行交叉应用和外部应用
如本文中所建议,对于普通的联接操作(INNER AND CROSS),它们之间没有性能差异。
使用差异会在您必须执行以下查询时到达:
CREATE FUNCTION dbo.fn_GetAllEmployeeOfADepartment(@DeptID AS INT)
RETURNS TABLE
AS
RETURN ( SELECT * FROM Employee E WHERE E.DepartmentID = @DeptID )
GO
SELECT * FROM Department D
CROSS APPLY dbo.fn_GetAllEmployeeOfADepartment(D.DepartmentID)
也就是说,当您必须与功能相关时。 这不能使用INNER JOIN来完成,这将给您错误“无法绑定多部分标识符“ D.DepartmentID”。” 此处,在读取每一行时,会将值传递给函数。 对我来说听起来很酷。 :)
#9楼
APPLY运算符的本质是允许FROM子句中运算符的左侧和右侧之间具有相关性。
与JOIN相比,输入之间的相关性是不允许的。
谈到APPLY运算符中的相关性,我的意思是在右侧我们可以输入:
- 派生表-作为具有别名的相关子查询
- 表值函数-具有参数的概念视图,其中参数可以引用左侧
两者都可以返回多个列和行。
#10楼
从技术上来说,这已经得到了很好的回答,但是让我举一个具体的例子说明它是多么有用:
假设您有两个表,客户表和订单。 客户有很多订单。
我想创建一个视图,为我提供有关客户以及他们最近完成的订单的详细信息。 仅使用JOINS,这将需要一些自联接和聚合,这并不理想。 但是使用Cross Apply,它超级简单:
SELECT *
FROM Customer
CROSS APPLY (SELECT TOP 1 *FROM OrderWHERE Order.CustomerId = Customer.CustomerIdORDER BY OrderDate DESC
) T
#11楼
cross apply
有时使您可以做inner join
无法做到的事情。
示例(语法错误):
select F.* from sys.objects O
inner join dbo.myTableFun(O.name) F
on F.schema_id= O.schema_id
这是一个语法错误 ,因为当与inner join
一起使用时,表函数只能将变量或常量作为参数。 (即,表函数参数不能依赖于另一个表的列。)
然而:
select F.* from sys.objects O
cross apply ( select * from dbo.myTableFun(O.name) ) F
where F.schema_id= O.schema_id
这是合法的。
编辑:或者,较短的语法:(由ErikE)
select F.* from sys.objects O
cross apply dbo.myTableFun(O.name) F
where F.schema_id= O.schema_id
编辑:
注意:Informix 12.10 xC2 +具有横向衍生表,而Postgresql(9.3+)具有横向子查询 ,可以使用类似的效果。
#12楼
好吧,我不确定这是否符合使用交叉申请与内部联接的理由,但是在使用交叉申请的论坛帖子中为我回答了此查询,因此我不确定是否使用内部联接的均等方法:
Create PROCEDURE [dbo].[Message_FindHighestMatches]-- Declare the Topical Neighborhood
@TopicalNeighborhood nchar(255)
从头开始
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ONCreate table #temp
(MessageID int,Subjects nchar(255),SubjectsCount int
)Insert into #temp Select MessageID, Subjects, SubjectsCount From MessageSelect Top 20 MessageID, Subjects, SubjectsCount,(t.cnt * 100)/t3.inputvalues as MatchPercentageFrom #temp cross apply (select count(*) as cnt from dbo.Split(Subjects,',') as t1join dbo.Split(@TopicalNeighborhood,',') as t2on t1.value = t2.value) as t
cross apply (select count(*) as inputValues from dbo.Split(@TopicalNeighborhood,',')) as t3Order By MatchPercentage descdrop table #temp
结束
什么时候应该在内部联接上使用交叉应用?相关推荐
- sql内部连接_SQL内部联接的分步演练
sql内部连接 Organizations are generating and analyzing unmatched volumes of data with each passing minut ...
- android studio文件内部存储,Android Studio使用内部存储上的文件创建diconary
即时通讯工具正在Android的Notes应用程序中使用. 问题:我不知道如何保存txt.我的内部存储上的应用程序文件.我已经用外部存储编码了它.这里是我的代码(MainActivity.java)A ...
- STM32F103内部弱上拉弱下拉电阻阻值的大小
内部上拉下拉电阻阻值典型值40K欧. 查STM32F103x6/STM32F103x8/STM32F103xB的DATASHEET的5.3.12 I/O port pin characteristic ...
- 【20保研】上海财经大学交叉科学研究院关于举办2019年“上财交叉科学研究院硕博连读选拔夏令营”的通知...
点击文末的阅读原文或者公众号界面左下角的保研夏令营或者公众号回复"夏令营"是计算机/软件等专业的所有保研夏令营信息集合,会一直更新的. 重要提示:交叉科学研究院将夏令营作为选拔20 ...
- 移动硬盘与电脑连接后 计算机中找不到,移动硬盘联接上电脑,可是打开我的电脑却找不到移动硬盘。...
你好知友! . ★电脑无法识别和使用移动硬盘的原因和解决办法: 一般来讲是因为USB接口的供电不足引起的. . 1.★换根数据线改善移动硬盘供电现状,如更换一根双USB头接入数据线. 2.如在笔记本电 ...
- mysql查询语法错误_MySQL内部联接查询语法错误
我是MySQL的新手,无法弄清楚这里出了什么问题.我有两张桌子.左表称为"锻炼".相关列是日期(日期类型)和ID(类型int). 右边的表称为Workout_locations(相 ...
- SQL 内部联接 – 如何在 SQL 和 MySQL 中联接 3 个表
使用数据库时,可能需要将几个不同表中的数据放在一起.本文将向您展示如何操作. 我已经在这里和这里写了关于SQL连接的文章,但让我们先花点时间回顾一下连接是如何工作的,特别是特定于MySQL的语法. S ...
- 确定sw1开关信号输入端口_基础教程15 Arduino端口内部的上拉功能
本专栏内容经修订后,已在豆瓣阅读集结成书出版: https://read.douban.com/ebook/106875966/read.douban.com 我是潘,曾经是个工程师.这是为 htt ...
- mysql 最大值 关联_mysql-关于最大值的内部联接表
我试图编写一个MySQL查询,在其中提取卖方的信息和她最受欢迎的产品.这取决于浏览量最多的产品,即MAX(page_views). 不过,以下查询只是拉出一种随机产品,而不是浏览量最多的产品. &qu ...
最新文章
- C语言求数字菱形,打印数字菱形,急啊,帮帮小女子啊。。。
- Leetcode 23 合并k个升序链表 (每日一题 20210722)
- 无向图g的邻接矩阵一定是_矩阵是图
- C#中的static、readonly与const的比较
- XHML教会我的一些东西-5
- 无线通信里的 UAV
- 服装企业二维码应用现状,如何建立二维码营销平台规则体系?
- 如何开会——高效会议八项原则
- kafka的全面知识点
- 购买弹性云服务器怎么部署网站,购买后怎么部署自己的云服务器
- html 动态加载的菜单 当菜单点击一下,打开接着又关闭
- android入门之系统架构和环境搭建
- NO-SQL(非关系型)数据库性能横向比较
- 【JAVA进阶篇】字符串的详细介绍
- hooks useRef 报错object is possibly undefined
- vs2015安装时遇到更新KB2919355
- 1998-2014年工企污染数据库
- 前后端分离的Java微信小程序B2C商城 H5+APP源码
- 「汇编」加深理解段地址*10H(*16)必须是16的倍数
- 直播平台源码中直播系统捕获音视频的步骤