SQLServer CROSS APPLY使用

在 SQL Server 中,CROSS APPLY 是一个用于将一个表值函数或子查询与一个表相关联的运算符。它类似于其他数据库系统中的 OUTER APPLY 运算符,但返回所有行,即使子查询结果为空。

使用 CROSS APPLY 可以将一个表值函数或子查询应用于另一个表或结果集的每一行,并返回一个结果集。这个结果集将与原始表或结果集的每一行相关联。

以下是一个简单的示例,演示如何使用 CROSS APPLY

假设我们有一个名为 Employees 的表,其中包含员工的姓名和部门信息。我们还有一个名为 Departments 的表,其中包含部门的名称和描述。我们想要获取每个员工的部门名称和描述。

sql 复制代码
SELECT E.EmployeeName, D.DepartmentName, D.DepartmentDescription  
FROM Employees E  
CROSS APPLY (  
    SELECT DepartmentName, DepartmentDescription  
    FROM Departments  
    WHERE DepartmentID = E.DepartmentID  
) D;

在这个示例中,CROSS APPLYDepartments 表与 Employees 表相关联,并返回每个员工的部门名称和描述。如果某个员工没有部门(即 DepartmentID 为 NULL),则子查询将返回空结果集,但由于是 CROSS APPLY,原始表的所有行仍然会被返回,但与部门相关的列将为 NULL。

总之,CROSS APPLY 用于将一个表值函数或子查询应用于另一个表的每一行,并返回一个与原始表相关联的结果集。

使用实例代码:

sql 复制代码
with cte as
(
select *,
cast(substring(month_info,7,3) as int) month_index --相对new_refreshdate的月份差值,用于计算具体的yyyymm
from (select new_totalreturnplanId,new_refreshdate,
ownerid,
isnull(convert(char(10) ,new_collectiondate_n, 120),'')+'|'+isnull(cast(new_collectionamount_n as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n as varchar),'') month_0,
isnull(convert(char(10) ,new_collectiondate_n1, 120),'')+'|'+isnull(cast(new_collectionamount_n1 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n1 as varchar),'') month_1,
isnull(convert(char(10) ,new_collectiondate_n2, 120),'')+'|'+isnull(cast(new_collectionamount_n2 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n2 as varchar),'') month_2,
isnull(convert(char(10) ,new_collectiondate_n3, 120),'')+'|'+isnull(cast(new_collectionamount_n3 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n3 as varchar),'') month_3,
isnull(convert(char(10) ,new_collectiondate_n4, 120),'')+'|'+isnull(cast(new_collectionamount_n4 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n4 as varchar),'') month_4,
isnull(convert(char(10) ,new_collectiondate_n5, 120),'')+'|'+isnull(cast(new_collectionamount_n5 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n5 as varchar),'') month_5,
isnull(convert(char(10) ,new_collectiondate_n6, 120),'')+'|'+isnull(cast(new_collectionamount_n6 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n6 as varchar),'') month_6,
isnull(convert(char(10) ,new_collectiondate_n7, 120),'')+'|'+isnull(cast(new_collectionamount_n7 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n7 as varchar),'') month_7,
isnull(convert(char(10) ,new_collectiondate_n8, 120),'')+'|'+isnull(cast(new_collectionamount_n8 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n8 as varchar),'') month_8,
isnull(convert(char(10) ,new_collectiondate_n9, 120),'')+'|'+isnull(cast(new_collectionamount_n9 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n9 as varchar),'') month_9,
isnull(convert(char(10) ,new_collectiondate_n10, 120),'')+'|'+isnull(cast(new_collectionamount_n10 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n10 as varchar),'') month_10,
isnull(convert(char(10) ,new_collectiondate_n11, 120),'')+'|'+isnull(cast(new_collectionamount_n11 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n11 as varchar),'') month_11,
isnull(convert(char(10) ,new_collectiondate_n12, 120),'')+'|'+isnull(cast(new_collectionamount_n12 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n12 as varchar),'') month_12,
isnull(convert(char(10) ,new_collectiondate_n13, 120),'')+'|'+isnull(cast(new_collectionamount_n13 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n13 as varchar),'') month_13,
isnull(convert(char(10) ,new_collectiondate_n14, 120),'')+'|'+isnull(cast(new_collectionamount_n14 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n14 as varchar),'') month_14,
isnull(convert(char(10) ,new_collectiondate_n15, 120),'')+'|'+isnull(cast(new_collectionamount_n15 as varchar),'')+'|'+isnull(cast(new_collectionamount_org_n15 as varchar),'') month_15
from new_totalreturnplanBase) SourceTable  --1.先把字段拼接起来 
UNPIVOT  --2.列转行
(collection_info FOR month_info IN (month_0, month_1,month_2,month_3,month_4,month_5,month_6,month_7,month_8,month_9,month_10,month_11,month_12,month_13,month_14,month_15)) AS UnpivotTable
)
select new_totalreturnplanId,new_refreshdate,ownerid, CONVERT(VARCHAR(6),dateadd(MONTH,month_index,new_refreshdate), 112) yyyymm,
d.[1] as new_collectiondate,
d.[2] as new_collectionamount,
d.[3] as new_collectionamount_org
from cte c
CROSS APPLY--将拼接的collection_info拆分成多列
(
   SELECT  [1], [2],[3]
FROM   
(select value,(ROW_NUMBER() over (order by (select 1))) num from string_split(c.collection_info,'|')) SourceTable  
PIVOT  
(  
max(value)  
FOR num IN ([1],[2],[3])  
) AS PivotTable
)d

这里 CROSS APPLY 的是一个拼接字符串string_split而得来的表.

心得:

1.通常我们需要得到多个字段的值一般会想到通过join关联表返回,CROSS APPLY某种意义上和表连接的功能相同;

2.当我们不合适或者无法使用表连接查询一个表的多个字段时(如上,根本没有可以关联的表),你不应该重复使用子查询来查询这些字段,而是使用CROSS APPLY,将需要通过子查询得到的所有字段统一通过CROSS APPLY查出来,实现子查询后置,而不是在select后重复使用子查询每个字段查询一次.

相关推荐
星空露珠5 小时前
28种颜色对应名称,
开发语言·数据库·算法·游戏·lua
踏月的造梦星球6 小时前
DM8 DSC 单机双实例部署
运维·开发语言·数据库
Database_Cool_6 小时前
企业级多模态分析计算引擎选型:首选 AnalyticDB MySQL 向量 + SQL + 实时一体化方案
数据库·sql·mysql
SelectDB6 小时前
从 Oracle、Hadoop 到 Apache Doris:哥瑞利泛半导体智能制造数据平台实践
数据库
ihuyigui6 小时前
海外签收通知短信接口
android·java·开发语言·前端·数据库·后端
海棠Flower未眠6 小时前
SpringBoot 消息死信队列(荣耀典藏版)
java·数据库·spring boot
Y3815326627 小时前
SERP API + Redis 缓存层:4 种方案对比与选型
数据库·redis·缓存
用户7783366132117 小时前
serpbase + GraphQL wrapper 实战:让 SERP 数据走 GraphQL schema
数据库·api
数字新视界7 小时前
信创动环监控品牌的技术架构及应用解析
数据库·物联网·需求分析·机房管理·动环监控
洵有兮8 小时前
sql注入通关笔记
数据库·笔记·sql·sql注入