在 SQL Server 中,CROSS APPLY
是一个用于将一个表值函数或子查询与一个表相关联的运算符。它类似于其他数据库系统中的 OUTER APPLY
运算符,但返回所有行,即使子查询结果为空。
使用 CROSS APPLY
可以将一个表值函数或子查询应用于另一个表或结果集的每一行,并返回一个结果集。这个结果集将与原始表或结果集的每一行相关联。
以下是一个简单的示例,演示如何使用 CROSS APPLY
:
假设我们有一个名为 Employees
的表,其中包含员工的姓名和部门信息。我们还有一个名为 Departments
的表,其中包含部门的名称和描述。我们想要获取每个员工的部门名称和描述。
SELECT E.EmployeeName, D.DepartmentName, D.DepartmentDescription
FROM Employees E
CROSS APPLY (
SELECT DepartmentName, DepartmentDescription
FROM Departments
WHERE DepartmentID = E.DepartmentID
) D;
在这个示例中,CROSS APPLY
将 Departments
表与 Employees
表相关联,并返回每个员工的部门名称和描述。如果某个员工没有部门(即 DepartmentID
为 NULL),则子查询将返回空结果集,但由于是 CROSS APPLY
,原始表的所有行仍然会被返回,但与部门相关的列将为 NULL。
总之,CROSS APPLY
用于将一个表值函数或子查询应用于另一个表的每一行,并返回一个与原始表相关联的结果集。
使用实例代码:
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后重复使用子查询每个字段查询一次.