一、功能介绍:

CROSS APPLY和OUTER APPLY是SQL Server中的一种连接操作,类似于JOIN语句可以将一张表与一个表函数或一个子查询进行关联。表函数是一种返回一个表类型的数据的函数,子查询是一个嵌套在外部查询中的查询。它们可以与表值函数或子查询配合使用,返回左表和右表的匹配结果。CROSS APPLY只返回有匹配结果的左表行,而OUTER APPLY返回所有的左表行,没有匹配结果的用NULL填充。

1.CROSS APPLY和OUTER APPLY的区别在于处理不匹配的行的方式:

  • CROSS APPLY只返回左表中与右表或函数匹配的行,类似于INNER JOIN。
  • OUTER APPLY返回左表中所有的行,如果没有与右表或函数匹配的行,则用NULL填充,类似于LEFT OUTER JOIN。

CROSS APPLY和OUTER APPLY的语法如下:

SELECT column_list
FROM table1
CROSS APPLY table_valued_function(table1.column)
-- or
SELECT column_list
FROM table1
CROSS APPLY (subquery) AS alias SELECT column_list
FROM table1
OUTER APPLY table_valued_function(table1.column)
-- or
SELECT column_list
FROM table1
OUTER APPLY (subquery) AS alias

2.CROSS APPLY和OUTER APPLY的用途有:

  • 与表函数关联,如使用系统函数或者自定义函数将一张表与一个返回表类型数据的函数进行关联,从而实现一对多的关系。
  • 与子查询关联,如使用聚合函数或窗口函数来计算每行的统计信息。
  • 重用列别名,如使用计算一个列的表达式,并在后续引用该表达式。

二、SQL Server数据库:

在SQL Server数据库创建tb1、tb2表及插入测试数据

create table tb1(id decimal(6,0),info varchar(10),age decimal(4,0));
insert into tb1 values(1,'A',22);
insert into tb1 values(2,'B',16);
insert into tb1 values(3,'C',28); create table tb2(id decimal(6,0),info varchar(10),age decimal(4,0));
insert into tb2 values(1,'A',22);
insert into tb2 values(2,'B',16);
insert into tb2 values(6,'D',35);

2.1:与子查询关联:

使用CROSS APPLY查询:

--将两个表直接连接,不需要任何的关联条件,产生的结果就是这两张表的笛卡儿集
SELECT d.* FROM tb1 d CROSS APPLY tb2; --将表tb1与表tb2使用子查询连接,使用左表的字段作为子查询的条件
SELECT * FROM tb1 d
CROSS APPLY (select * from tb2 where id=d.id) b;

返回结果:

  • CROSS APPLY 操作仅返回左表表达式(在其最终输出中)中与右表表达式匹配的那些行。 CROSS APPLY 类似于 INNER JOIN,更准确地说类似于具有相关子查询的 CROSS JOIN,其隐式联接条件为 1=1。
SELECT * FROM tb1 a
cross join tb2 b
where a.id=b.id ;

使用OUTER APPLY查询:

SELECT * FROM tb1 d
OUTER APPLY (select * from tb2 where id=d.id) b;

返回结果:

  • OUTER APPLY 操作返回左表表达式中的所有行,不管其与右表表达式的匹配情况。 对于右表表达式中没有相应匹配项的那些行,在右表表达式的列中返回 NULL 值。 如果没有与右表或函数匹配的行,则用NULL填充。OUTER APPLY 等效于 LEFT OUTER JOIN。
SELECT * FROM tb1 a
LEFT OUTER JOIN tb2 b
on a.id=b.id ;

2.2:与表函数关联:

CREATE TABLE EPD (
EmpId int PRIMARY KEY,
EmpFirstName VARCHAR(50),
EmpLastName VARCHAR(50),
Department VARCHAR(50),
DepartID INT
); CREATE TABLE EPS (
EmpID INT,
EmpFullName VARCHAR(80),
EmpSalary INT,
EmpWorkingYears INT,
DepartID INT
); insert into EPD values(1001,'Kate','Thomas','IT',2);
insert into EPD values(1002,'John','Wills','IT',2);
insert into EPD values(1003,'Branda','Pat','Accounts',3);
insert into EPD values(1004,'Sofia','Kaul','HR',1);
insert into EPD values(1005,'Tim','Stout','IT',2);
insert into EPD values(1006,'Mick','Presto','Accounts',3);
insert into EPD values(1007,'Nwwhile','Nwwhile','Nwwhile',NULL); insert into EPS values(1001,'Kate Thimas',35000,3,2);
insert into EPS values(1002,'John Wills',25000,2,2);
insert into EPS values(1003,'Branda Pat',20000,2,3);
insert into EPS values(1004,'Sofia Kaul',18000,1,1);
insert into EPS values(1005,'Tim Stout',25000,2,2);
insert into EPS values(1006,'Mick Presto',28000,3,3);
insert into EPS values(null,'Nwwhile Nwwhile',8000,1,NULL);
insert into EPS values(null,'Hello World',5000,1,NULL); CREATE FUNCTION fn_Salar (@DepartmentID int)
RETURNS TABLE
AS RETURN
(
SELECT
EmpID, EmpFullName,
EmpSalary+5000 AS Salaryinc
FROM EPS
WHERE DepartID = @DepartmentID
);

使用CROSS APPLY查询:

--执行此查询看返回是否符合预期
SELECT EmpID, Salaryinc FROM fn_Salar(2)
--使用CROSS APPLY关联表值函数fn_Salar
SELECT e.EmpFirstName,
e.EmpLastName,
f.Salaryinc
FROM EPD AS e
CROSS APPLY fn_Salar (e.DepartID) AS f

返回结果:

使用OUTER APPLY查询:

--执行此查询看返回是否符合预期
SELECT EmpID, Salaryinc FROM fn_Salar(2)
--使用CROSS APPLY关联表值函数fn_Salar
SELECT e.EmpFirstName,
e.EmpLastName,
f.Salaryinc
FROM EPD AS e
OUTER APPLY fn_Salar (e.DepartID) AS f

返回结果:

2.3:引用列别名:

使用CROSS APPLY查询:

--直接在CROSS APPLY查询引用查询出的列进行计算
select p.*,calc_salay
FROM EPS AS p
CROSS APPLY (select (p.EmpSalary/1000)) s(calc_salay)
CROSS APPLY (select * from EPD where EmpID=p.EmpID) f

返回结果:

使用OUTER APPLY查询:

select p.*,calc_salay
FROM EPS AS p
OUTER APPLY (select (p.EmpSalary/1000)) s(calc_salay)
OUTER APPLY (select * from EPD where EmpID=p.EmpID) f

返回结果:

2.4:SQL Server数据库CROSS APPLY、OUTER APPLY总结:

  • CROSS APPLY仅返回左表表达式(在其最终输出中)中与右表表达式匹配的那些行。 CROSS APPLY 类似于 INNER JOIN,更准确地说,类似于具有相关子查询的 CROSS JOIN,其隐式联接条件为 1=1。
  • OUTER APPLY返回左表表达式中的所有行,而不管其与右表表达式的匹配情况。 对于右表表达式中没有相应匹配项的那些行,它在右表表达式的列中返回 NULL 值。 因此OUTER APPLY 等效于 LEFT OUTER JOIN。
  • 当右侧有一个表值函数或子查询并且你希望为左侧表表达式中的每一行计算此表值函数或子查询时,就需要使用 APPLY。 在某些情况下使用 APPLY 运算可以提高查询性能。

三、KingbaseES数据库实现CROSS APPLY、OUTER APPLY功能:

KingbaseES数据库使用lateral表达式可以在FROM子句中引用之前的表或子查询的列。lateral表表达式可以用来实现一些复杂的查询逻辑,如对每一行执行一个带参数的子查询,或者对多个函数返回的结果集进行联合。使用表连接+lateral可以实现CROSS APPLY、OUTER APPLY功能。

KingbaseES数据库创建tb1、tb2测试表:

create table tb1(id number(6,0),info varchar(10),age number(4,0));
insert into tb1 values(1,'A',22);
insert into tb1 values(2,'B',16);
insert into tb1 values(3,'C',28); create table tb2(id number(6,0),info varchar(10),age number(4,0));
insert into tb2 values(1,'A',22);
insert into tb2 values(2,'B',16);
insert into tb2 values(6,'D',35);

3.1:lateral结合子查询:

SELECT d.*  FROM tb1 d CROSS join tb2;
ID | INFO | AGE
----+------+-----
1 | A | 22
1 | A | 22
1 | A | 22
2 | B | 16
2 | B | 16
2 | B | 16
3 | C | 28
3 | C | 28
3 | C | 28
(9 rows) --使用cross join结合lateral查询
SELECT * FROM tb1 d
CROSS JOIN lateral (select * from tb2 where id=d.id) b;
ID | INFO | AGE | ID | INFO | AGE
----+------+-----+----+------+-----
1 | A | 22 | 1 | A | 22
2 | B | 16 | 2 | B | 16
(2 rows) --或者把lateral放from子句中
SELECT * FROM tb1 d,lateral(select * from tb2 where id=d.id);
ID | INFO | AGE | ID | INFO | AGE
----+------+-----+----+------+-----
1 | A | 22 | 1 | A | 22
2 | B | 16 | 2 | B | 16
(2 rows) --使用left outer join结合lateral查询
SELECT * FROM tb1 d
LEFT OUTER JOIN lateral(select * from tb2 where id=d.id) b on true; ID | INFO | AGE | ID | INFO | AGE
----+------+-----+----+------+-----
1 | A | 22 | 1 | A | 22
2 | B | 16 | 2 | B | 16
3 | C | 28 | | |
(3 rows) --使用left join结合lateral查询
SELECT * FROM tb1 d
LEFT JOIN lateral(select * from tb2 where id=d.id) b on true; ID | INFO | AGE | ID | INFO | AGE
----+------+-----+----+------+-----
1 | A | 22 | 1 | A | 22
2 | B | 16 | 2 | B | 16
3 | C | 28 | | |
(3 rows)

3.2:lateral结合函数查询:

准备环境:

CREATE TABLE EPD (
EmpId int PRIMARY KEY,
EmpFirstName VARCHAR(50),
EmpLastName VARCHAR(50),
Department VARCHAR(50),
DepartID INT
); CREATE TABLE EPS (
EmpID INT,
EmpFullName VARCHAR(80),
EmpSalary INT,
EmpWorkingYears INT,
DepartID INT
); insert into EPD values(1001,'Kate','Thomas','IT',2);
insert into EPD values(1002,'John','Wills','IT',2);
insert into EPD values(1003,'Branda','Pat','Accounts',3);
insert into EPD values(1004,'Sofia','Kaul','HR',1);
insert into EPD values(1005,'Tim','Stout','IT',2);
insert into EPD values(1006,'Mick','Presto','Accounts',3);
insert into EPD values(1007,'Nwwhile','Nwwhile','Nwwhile',NULL); insert into EPS values(1001,'Kate Thimas',35000,3,2);
insert into EPS values(1002,'John Wills',25000,2,2);
insert into EPS values(1003,'Branda Pat',20000,2,3);
insert into EPS values(1004,'Sofia Kaul',18000,1,1);
insert into EPS values(1005,'Tim Stout',25000,2,2);
insert into EPS values(1006,'Mick Presto',28000,3,3);
insert into EPS values(null,'Nwwhile Nwwhile',8000,1,NULL);
insert into EPS values(null,'Hello World',5000,1,NULL); CREATE or replace FUNCTION fn_Salar(DepartmentID int)
RETURNS TABLE (EmpID int, EmpFullName varchar2(80), Salaryinc int) AS
BEGIN
RETURN QUERY SELECT EmpID,EmpFullName,EmpSalary+5000 AS Salaryinc FROM EPS WHERE DepartID=DepartmentID;
END;

使用CROSS APPLY查询:

--执行此查询看返回是否符合预期
SELECT EmpID, Salaryinc FROM fn_Salar(2); EMPID | EMPFULLNAME | SALARYINC
-------+-------------+-----------
1001 | Kate Thimas | 40000
1002 | John Wills | 30000
1005 | Tim Stout | 30000
(3 rows) --使用CROSS APPLY关联表值函数fn_Salar
SELECT e.EmpFirstName,
e.EmpLastName,
f.Salaryinc
FROM EPD AS e
CROSS JOIN lateral fn_Salar (e.DepartID) AS f;
--或者
SELECT e.EmpFirstName,
e.EmpLastName,
f.Salaryinc
FROM EPD AS e
CROSS JOIN fn_Salar (e.DepartID) AS f; --返回结果
EMPFIRSTNAME | EMPLASTNAME | SALARYINC
--------------+-------------+-----------
Kate | Thomas | 40000
Kate | Thomas | 30000
Kate | Thomas | 30000
John | Wills | 40000
John | Wills | 30000
John | Wills | 30000
Branda | Pat | 25000
Branda | Pat | 33000
Sofia | Kaul | 23000
Tim | Stout | 40000
Tim | Stout | 30000
Tim | Stout | 30000
Mick | Presto | 25000
Mick | Presto | 33000
(14 rows)

使用OUTER APPLY查询:

--使用CROSS APPLY关联表值函数fn_Salar
SELECT e.EmpFirstName,
e.EmpLastName,
f.Salaryinc
FROM EPD AS e
LEFT JOIN fn_Salar (e.DepartID) AS f on true;
--或者
SELECT e.EmpFirstName,
e.EmpLastName,
f.Salaryinc
FROM EPD AS e
LEFT JOIN lateral fn_Salar (e.DepartID) AS f on true; --返回结果
EMPFIRSTNAME | EMPLASTNAME | SALARYINC
--------------+-------------+-----------
Kate | Thomas | 40000
Kate | Thomas | 30000
Kate | Thomas | 30000
John | Wills | 40000
John | Wills | 30000
John | Wills | 30000
Branda | Pat | 25000
Branda | Pat | 33000
Sofia | Kaul | 23000
Tim | Stout | 40000
Tim | Stout | 30000
Tim | Stout | 30000
Mick | Presto | 25000
Mick | Presto | 33000
Nwwhile | Nwwhile |
(15 rows)

3.3:引用列别名:

使用CROSS APPLY查询:

select p.*,calc_salay
FROM EPS AS p
CROSS JOIN lateral(select (p.EmpSalary/1000)) s(calc_salay)
CROSS JOIN lateral(select * from EPD where EmpID=p.EmpID) f; --返回结果
EMPID | EMPFULLNAME | EMPSALARY | EMPWORKINGYEARS | DEPARTID | CALC_SALAY
-------+-------------+-----------+-----------------+----------+------------
1001 | Kate Thimas | 35000 | 3 | 2 | 35
1002 | John Wills | 25000 | 2 | 2 | 25
1003 | Branda Pat | 20000 | 2 | 3 | 20
1004 | Sofia Kaul | 18000 | 1 | 1 | 18
1005 | Tim Stout | 25000 | 2 | 2 | 25
1006 | Mick Presto | 28000 | 3 | 3 | 28
(6 rows)

使用OUTER APPLY查询:

select p.*,calc_salay
FROM EPS AS p
LEFT OUTER JOIN lateral(select (p.EmpSalary/1000)) s(calc_salay) on true
LEFT OUTER JOIN lateral(select * from EPD where EmpID=p.EmpID) f on true;
--或者
select p.*,calc_salay
FROM EPS AS p
LEFT JOIN lateral(select (p.EmpSalary/1000)) s(calc_salay) on true
LEFT JOIN lateral(select * from EPD where EmpID=p.EmpID) f on true; --返回结果
EMPID | EMPFULLNAME | EMPSALARY | EMPWORKINGYEARS | DEPARTID | CALC_SALAY
-------+-----------------+-----------+-----------------+----------+------------
1001 | Kate Thimas | 35000 | 3 | 2 | 35
1002 | John Wills | 25000 | 2 | 2 | 25
1003 | Branda Pat | 20000 | 2 | 3 | 20
1004 | Sofia Kaul | 18000 | 1 | 1 | 18
1005 | Tim Stout | 25000 | 2 | 2 | 25
1006 | Mick Presto | 28000 | 3 | 3 | 28
| Nwwhile Nwwhile | 8000 | 1 | | 8
| Hello World | 5000 | 1 | | 5
(8 rows)

3.4:KingbaseES数据库lateral子查询使用场景

  • 在from子句中使用一个带参数的函数,而参数来自于前面的表或子查询。
  • 在from子句中使用一个聚合函数,而分组列来自于前面的表或子查询。
  • 在from子句中使用一个窗口函数,而窗口分区列来自于前面的表或子查询。

KingbaseES数据库改写SQL Server数据库CROSS APPLY和OUTER APPLY的更多相关文章

  1. [PowerDesign]将数据库从SQL Server数据库转换为MySQL

    原文:[PowerDesign]将数据库从SQL Server数据库转换为MySQL 一.迁移Database Schema. 首先使用Sybase Powerdesigner的逆向工程功能,逆向出S ...

  2. Oracle 数据库和Sql Server数据库的区别

    Oracle数据库的访问方式,和SqlServer数据库是有很大差别的,下面用图来说明: 1.Sql Server数据库 SqlServer数据库的访问方式,大致是:假设用户通过sa登录SqlServ ...

  3. Access数据库和SQL Server数据库在实际应用中的区别

    1.在Access数据库中简历查询语句的步骤 --> 打开你的MDB --> 在数据库窗口中,点击“查询”,或在“视图”菜单中选择“数据库对象”-> “查询” --> 点击数据 ...

  4. 图解如何 将Excel里的数据导入到sql server数据库中

    项目中,经常会碰到如何将Excel里的数据导入到sql server中的问题. 下面,图解如何实现导入Excel中的数据到sql server 2008 R2: Excel截图如下: 查询pub数据库 ...

  5. SQL Server 数据库项目

    ylbtech-.NET Framework: SQL Server 数据库项目 SQL Server 数据库项目 类型:SQL Server 用于创建 SQL Server 数据库的项目 1. 新建 ...

  6. SQL 注入之:SQL Server 数据库

    郑重声明: 本笔记编写目的只用于安全知识提升,并与更多人共享安全知识,切勿使用笔记中的技术进行违法活动,利用笔记中的技术造成的后果与作者本人无关.倡导维护网络安全人人有责,共同维护网络文明和谐. SQ ...

  7. SQL Server中CROSS APPLY和OUTER APPLY的应用详解

    SQL Server数据库操作中,在2005以上的版本新增加了一个APPLY表运算符的功能.新增的APPLY表运算符把右表表达式应用到左表表达式中的每一行.它不像JOIN那样先计算那个表表达式都可以, ...

  8. SQL Server - 数据库初识

      在互联网笔试中,常遇到数据库的问题,遂来简单总结,注意,以 Sql Server 数据库为例. 数据库 数据库系统,Database System,由数据库和数据库管理系统组成. 数据库,Data ...

  9. 3. SQL Server数据库状态监控 - 可用空间

    原文:3. SQL Server数据库状态监控 - 可用空间 数据库用来存放数据,那么肯定需要存储空间,所以对磁盘空间的监视自然就很有必要了. 一. 磁盘可用空间 1. 操作系统命令或脚本.接口或工具 ...

  10. 5. SQL Server数据库性能监控 - 当前请求

    原文:5. SQL Server数据库性能监控 - 当前请求 对于在线运行的系统,当前数据库性能监控,通常监视以下几点: (1) 是否有阻塞 (Blocking); (2) 是否有等待 (Waitin ...

随机推荐

  1. [技术选型与调研] 流程引擎/工作流引擎:Activiti、Flowable、Camunda

    1 概述:流程与流程引擎 低代码平台.办公自动化(OA).BPM平台.工作流系统均需要流程引擎功能 [工作流引擎的三大功能] 1)验证当前过程状态:在给定当前状态的情况下,检查是否有效执行任务. 2) ...

  2. 【Unity3D】Bloom特效

    1 Bloom 特效原理 ​ Bloom 特效是指:将画面中较亮的区域向外扩散,造成一种朦脓的效果.实现 Bloom 特效,一般要经过 3 个阶段处理:亮区域检测.高斯模糊.Bloom 合成. ​ 本 ...

  3. leetcode - 中序遍历

    给定一个二叉树的根节点 root ,返回 它的 中序 遍历 . 示例 1: 输入:root = [1,null,2,3] 输出:[1,3,2] 示例 2: 输入:root = [] 输出:[] 示例 ...

  4. 正则表达式re模块---day18

    1.匹配单个字符 import re lst = re.findall(正则表达式,要匹配的字符串) 返回的是列表,按照正则表达式匹配到的内容都扔到列表中 # ### 1.预定义字符集 # \d 匹配 ...

  5. 无所不谈,百无禁忌,Win11本地部署无内容审查中文大语言模型CausalLM-14B

    目前流行的开源大语言模型大抵都会有内容审查机制,这并非是新鲜事,因为之前chat-gpt就曾经被"玩"坏过,如果没有内容审查,恶意用户可能通过精心设计的输入(prompt)来操纵L ...

  6. git commit大文件后无法删除或撤回

    可以使用版本回退的功能 先用git log 查看历史提交 用 git reset --soft 上面的编号 回退到历史提交的版本 再重新commit即可

  7. mybatis查询大批量数据的几种方式

    问题背景 公司里有很多需要跑批数据的场景,这些数据几十万到几千万不等,目前我们采用的是分页查询,但是分页查询有个深度分页问题,上百万的数据就会查询的很慢 常规解决方案 全量查询 分页查询 流式查询 游 ...

  8. ThreadLocal父子间通信的四种解决方案

    ThreadLocal父子间通信的四种解决方案 ThreadLocal 是存储在线程栈帧中的一块数据存储区域,其可以做到线程与线程之间的读写隔离. 但是在我们的日常场景中,经常会出现父线程需要向子线程 ...

  9. 函数指针 int (*add)( )

    原文 首先它是一个指针,一个指向函数的指针,在内存空间中存放的是函数的地址: int Add(int x,int y) { return x+y; } int main() { printf(&quo ...

  10. favorite 单词学习 主要是发音 fa - vor - it 注意 ri不连读 是自然带出来的r的尾音

    favorite 单词学习 主要注意发音 [ ˈfeɪ v(ə)r ɪt ] 主要是发音 fa - vor - it 注意 ri不连读 是自然带出来的r的尾音 favor : 来自拉丁语favere, ...