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

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

时间:2023-09-19 18:59:07浏览次数:38  
标签: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;

返回结果:

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

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

相关文章

  • KingbaseES数据库安装PostGIS扩展GEOSUnaryunionPrec错误
    一、问题现象:KingbaseESV008R006C007B0012数据库集群安装PostGIS扩展插件报错。createextensionpostgis;ERROR:couldnotloadiibrary"/opt/kingbase/cluster/kingbase/lib/postgis-3.so”:/opt/kingbase/cluster/kingbase/lib/postgis-3.so:undefinedsymbo1:GEOSUnar......
  • KingbaseES数据库分区表添加主键与索引的建议
    一、初始化测试环境#数据库版本信息KingbaseESV008R006C007B0012onx86_64-pc-linux-gnu,compiledbygcc(GCC)4.1.220080704(RedHat4.1.2-46),64-bit1.创建分区表:createtabletb(idbigint,statdate,nobigint,pdatedate,infovarchar2(50))partitionbyra......
  • Mysql数据库的索引
    1.索引的概念索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址(类似于c语言的链表通过指针指向数据记录的内存地址)。使用索引后可以不用扫描全表来定位某行的数据,而是先通过索引表找到该行数据对应的物理地址然后访问相应的数据,因此能加......
  • KingbaseES 数据库中不同user的视图访问授权
    前言本文的目的是实现u1用户访问ud用户下的视图权限。测试登录system用户并创建schema,user,并授权schema的有关权限给ud用户TEST=#selectcurrent_user;current_user--------------system(1row)TEST=#createschemaud;CREATESCHEMATEST=#TEST=#createuserud;......
  • KingbaseES数据库导入数据invalid byte sequence for encoding
    一、适用版本:KingbaseES数据库所有版本。二、问题现象:使用备份的数据进行还原,还原过程中发生异常。日志信息:sys_restore:connectingtodatabaseforrestoresys_restore:creatingTABLE"public.table_name"sys_restore:creatingCOMMENT"public.COLUMNtable_name.co......
  • openGauss学习笔记-74 openGauss 数据库管理-创建和管理视图
    openGauss学习笔记-74openGauss数据库管理-创建和管理视图74.1背景信息当用户对数据库中的一张或者多张表的某些字段的组合感兴趣,而又不想每次键入这些查询时,用户就可以定义一个视图,以便解决这个问题。视图与基本表不同,不是物理上实际存在的,是一个虚表。数据库中仅存放视图的......
  • Mysql数据库的用户管理
    1.用户管理的具体操作1.1新建用户1.2修改用户密码1.3删除用户1.4修改用户名1.5忘记root密码时怎么重置密码1.先修改mysql的配置文件,在/etc/my.cnf下 3.输入命令修改user表中root的密码4.再修改mysql配置文件,改回去,之后重启服务,这样就修改了root用户的密......
  • 1. 初识数据库
    ###数据库的本质```python"""本质其实就是一款基于网络通信的应用程序那其实每个人都可以开发一款数据库软件因为它仅仅就是一个基于网络通信的应用程序也就意味着数据库软件其实有很多很多 关系型数据库 MySQL、oracle、db2、access、sqlserver 非关系型数据库 redis、mon......
  • 【HarmonyOS】元服务卡片router实现跳转到指定页面
    ​【关键字】元服务卡片、router跳转不同页面 【写在前面】本篇文章主要介绍开发元服务卡片时,如何实现从卡片中点击事件跳转到指定的应用内页面功能。此处以JSUI开发服务卡片为例,JS卡片支持组件设置action,包括router事件和message事件,其中router事件用于应用跳转,message事件......
  • Mysql-主从数据库配置
    两台linux服务器,修改主机名为mysql1,mysql2  1.修改主机名 服务器11hostnamemysql1 服务器21hostnamemysql22.关闭防火墙及SElinux服务mysql11setenforce02systemctlstopfirewalldmysql21setenforce02systemctlstopfirewalld3.配置hosts文件m......