首页 > 数据库 >KingbaseES数据库改写SQL Server数据库CROSS APPLY和OUTER APPLY

KingbaseES数据库改写SQL Server数据库CROSS APPLY和OUTER APPLY

时间:2023-06-12 14:44:57浏览次数:41  
标签:insert OUTER 数据库 CROSS values APPLY into

 

一、功能介绍:

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;

返回结果:

image-20230607185206128

  • 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;

返回结果:

image-20230607185403519

  • 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

返回结果:

image-20230607202026161

使用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

返回结果:

image-20230607202243195

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

返回结果:

image-20230607212247522

使用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

返回结果:

image-20230607212320153

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子句中使用一个窗口函数,而窗口分区列来自于前面的表或子查询。

标签:insert,OUTER,数据库,CROSS,values,APPLY,into
From: https://www.cnblogs.com/nwwhile/p/17474994.html

相关文章

  • SQL查询实战:大学数据库
    SQL查询实战:大学数据库原创 升哥 赛博升哥 2023-05-1418:46 发表于北京收录于合集#技术23个#数据库2个hello大家好,我是升哥。最近在学数据库,把重要主题笔记分享给大家。这次是大学数据库SQL查询实战,在MySQL上测试通过。关于导入数据库用到的SQL文件:后台......
  • vue Router的原理及传参方法
    VueRouter是Vue.js官方的路由管理器,它和Vue.js的核心深度集成,可以非常方便地实现单页面应用程序(SPA)的路由功能。VueRouter的原理主要是通过监听URL的变化,根据不同的URL显示不同的组件,从而实现页面的切换和跳转。具体来说,VueRouter的原理包括以下几个方面:路由配置......
  • 十分钟了解Mongodb数据库
    前言:本文可能比较长,主要分为3个部分。1.mongodb的简介。2.mongodb的安装。3.mongodb查询指令,大家可以根据选择进行阅读。 1.2什么是MongoDBMongoDB是一个跨平台的,面向文档的数据库,是当前NoSQL数据库产品中最热门的一种。它介于关系数据库和非关系数据库之间,是非关系数据库当......
  • hj_screw导出数据库表文档
    #要不要排除掉依赖,需要视项目导入的依赖情况而定.#这要排除掉依赖,主要是因为项目使用的log4j2排除了boot自身的日志具体如下:<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>......
  • 数据库关联查询--笛卡尔积
    概念笛卡尔乘积是指在数学中,两个集合X和Y的笛卡尔积(Cartesianproduct),又称直积,表示为X×Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员.设A和B是两个集合,存在一个集合,他的元素是用A中元素为第一元素,B中元素为第二元素构成的有序二元组。称它为A和B的笛卡......
  • SpringBoot自带ThreadPoolTaskScheduler实现数据库管理定时任务
    最近做了一个需求:将定时任务保存到数据库中,并在页面上实现定时任务的开关,以及更新定时任务时间后重新创建定时任务。于是想到了SpringBoot中自带的ThreadPoolTaskScheduler。在SpringBoot中提供的ThreadPoolTaskScheduler这个类,该类提供了一个schedule(Runnabletask,Triggert......
  • 浏览器关闭后动态更改数据库数据
    窗口:卸载前事件   beforeunload当窗口、文档及其资源即将卸载时,将触发 beforeunload 事件。此时,文档仍然可见,并且事件仍可取消。此事件使网页能够触发确认对话框,询问用户是否确实要离开页面。如果用户确认,浏览器将导航到新页面,否则将取消导航。 //浏览器刷新和退出提......
  • postgresml 基于postgres 的ai 应用数据库
    postgresml基于postgres的ai应用数据库,我们可以基于sql使用开源模型进行训练,实际上如果了解pg的化pg实际也有一个开源的madlib也属于机器学习领域的不错选择说明如果测试使用的,注意postgresmldocker镜像很大,同时需要自己构建会比较慢,后边我会介绍下使用参考资料https......
  • springboot+vue留守儿童爱心网站,附源码+数据库+论文+PPT,远程包安装运行
    1、项目介绍留守儿童爱心网站采用了B/S结构,JAVA作为开发语言,数据库采用了B/S结构,Mysql数据库进行开发。该系统包括前台操作,后台由管理员和用户两个部分,一方面,为用户提供首页、宣传新闻、志愿活动、爱心捐赠、个人中心、后台管理等功能;另一方面,为管理员提供首页、个人中心、用户管......
  • Spring配置动态数据库
    前言本文主要介绍使用springboot配置多个数据库,即动态数据库开始搭建首先创建一个SpringWeb项目——dynamicdb(spring-boot2.5.7)然后引入相关依赖lombok、swagger2、mybatis-plus,如下:<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/......