
openGauss 7.0新特性解析:CROSS APPLY如何实现跨表行间计算?
学习下7.0版本的新特性,发现7.0版本在7.0.0 RC-1版本新增了对cross apply join的支持,并且在官方文档中,介绍cross join等效于inner join,于是想着整理下哥儿几个的用法,以及三者的区别。out join对应的,在7.0版本也支持了out apply语法,应用out apply的时候,在右侧也可以直接引用左侧的表,如果大家感兴趣,将在后面的文章中继续说明。
一晃一年多过去,openGauss都推出7.0的版本了,于是打开what’s new学习下7.0版本的新特性,发现7.0版本在7.0.0 RC-1版本新增了对cross apply join的支持,并且在官方文档中,介绍cross join等效于inner join,于是想着整理下哥儿几个的用法,以及三者的区别。
一、哥仨的相同点
-
均用于多表数据关联查询;
-
均通过组合不同表数据生成新结果集;
-
执行过程都涉及表之间的行匹配逻辑。
二、核心区别
1. INNER JOIN
-
必须指定ON条件进行行匹配;
-
仅返回满足ON后面所跟的关联条件的记录;
-
典型场景:关联部门表和员工表。
2. CROSS JOIN
-
无需指定关联条件;
-
返回笛卡尔积(所有行组合),两两交叉;
-
典型场景:生成组合测试数据。
-
右侧表达式不可引用左表及其字段
3. CROSS APPLY
-
右侧表达式可引用左表字段;
-
支持表值函数动态计算;
-
典型场景:逐行计算关联子查询。
三、示例说明
示例表结构
1.部门表
openGauss=# select * from dept;
dept_id | dept_name | dept_manager
---------+-----------+--------------
1 | marketing |
2 | sales |
3 | develop |
4 | finacial | 41
(4 rows)
2.员工表
openGauss=# select * from employ;
emp_id | emp_name | dept_id
--------+------------+---------
11 | zhaofeng | 1
12 | zhangfeng2 | 1
21 | lifang | 2
22 | lifang2 | 2
31 | nezha | 3
32 | nezha2 | 3
(6 rows)
1. INNER JOIN示例
SELECT e.emp_name, d.dept_name
FROM employ e
INNER JOIN dept d
ON e.dept_id = d.dept_id;
执行结果:
返回部门表中dept_id和员工表中dept_id相同的数据。
openGauss=# SELECT e.emp_name,d.dept_name FROM employ e INNER JOIN dept d ON e.dept_id = d.dept_id;
emp_name | dept_name
------------+-----------
zhaofeng | marketing
zhangfeng2 | marketing
lifang | sales
lifang2 | sales
nezha | develop
nezha2 | develop
(6 rows)
2. CROSS JOIN示例
SELECT e.name, d.dept_name
FROM employ e
CROSS JOIN departments d;
执行结果是返回所有员工表中的数据和部门表中的数据的交叉组合结果:
openGauss=# SELECT e.emp_name,d.dept_name FROM employ e CROSS JOIN dept d;
emp_name | dept_name
------------+-----------
zhaofeng | marketing
zhaofeng | sales
zhaofeng | develop
zhaofeng | finacial
zhangfeng2 | marketing
zhangfeng2 | sales
zhangfeng2 | develop
zhangfeng2 | finacial
lifang | marketing
lifang | sales
lifang | develop
lifang | finacial
lifang2 | marketing
lifang2 | sales
lifang2 | develop
lifang2 | finacial
nezha | marketing
nezha | sales
nezha | develop
nezha | finacial
nezha2 | marketing
nezha2 | sales
nezha2 | develop
nezha2 | finacial
(24 rows)
返回结果记录条数为员工表记录条数(6)*部门表记录条数(4)=24条。由于该操作返回结果为笛卡尔积,在实际业务系统中要谨慎使用。
如官网所说,我们尝试执行下inner join on (true), 以1=1构造true条件,执行结果如下所示:
openGauss=# SELECT e.emp_name,d.dept_name FROM employ e INNER JOIN dept d ON 1=1;
emp_name | dept_name
------------+-----------
zhaofeng | marketing
zhaofeng | sales
zhaofeng | develop
zhaofeng | finacial
zhangfeng2 | marketing
zhangfeng2 | sales
zhangfeng2 | develop
zhangfeng2 | finacial
lifang | marketing
lifang | sales
lifang | develop
lifang | finacial
lifang2 | marketing
lifang2 | sales
lifang2 | develop
lifang2 | finacial
nezha | marketing
nezha | sales
nezha | develop
nezha | finacial
nezha2 | marketing
nezha2 | sales
nezha2 | develop
nezha2 | finacial
(24 rows)
不过在cross join中,右侧不能引用左侧的表或者列,否则会报错,如下所示:
openGauss=# SELECT d.dept_name,v.emp_id FROM dept d CROSS join (SELECT * FROM employ e WHERE e.dept_id = d.dept_id) v WHERE d.dept_name IN ('marketing', 'sales') ORDER BY d.dept_name, v.emp_id;
ERROR: invalid reference to FROM-clause entry for table "d"
LINE 1: ...SS join (SELECT * FROM employ e WHERE e.dept_id = d.dept_id)...
^
HINT: There is an entry for table "d", but it cannot be referenced from this part of the query.
但是cross apply就可以引用左侧的表了。
3. CROSS APPLY示例
openGauss=# SELECT d.dept_name,v.emp_id,v.emp_name FROM dept d CROSS apply (SELECT * FROM employ e WHERE e.dept_id = d.dept_id) v WHERE d.dept_name IN ('marketing', 'sales') ORDER BY d.dept_name, v.emp_id;
dept_name | emp_id | emp_name
-----------+--------+------------
marketing | 11 | zhaofeng
marketing | 12 | zhangfeng2
sales | 21 | lifang
sales | 22 | lifang2
(4 rows)
执行结果返回的是符合部门过滤条件的,以及e.dept_id = d.dept_id的记录。
根因溯源
那么为什么cross apply会支持右边的子查询可以引用左表的内容呢?
这个和cross apply语法的执行机制有关。CROSS APPLY 的核心逻辑是 对左表的每一行,动态计算右表表达式(通常是表值函数或子查询),并将结果与左表当前行组合。这种“行间关联”机制允许右表表达式直接引用左表的字段,因为它的计算是 基于左表当前行的上下文。而CROSS JOIN 在逻辑上会先展开两表的笛卡尔积,此时右表子查询无法感知左表的单行上下文。
Cross join语法在实际业务中也有很多适用的场景,体现出他特有的灵活,高效以及易读易理解的优势。
灵活性:解决需要基于左表每行动态关联右表的场景(如分页、TOP-N、函数调用)。
性能优化:避免先生成笛卡尔积再过滤的巨大开销。
语义清晰:直观表达“逐行处理”的业务逻辑。
后记
相应的,和out join对应的,在7.0版本也支持了out apply语法,应用out apply的时候,在右侧也可以直接引用左侧的表,如果大家感兴趣,将在后面的文章中继续说明。
本文作者
本文内容来自于数据库领域资深技术专家赵锋老师,希望我们的文章正好能解决你的问题。
更多推荐
所有评论(0)