浅析REGEXP_SUBSTR,PRIOR,CONNECT BY

业务场景

teacher表中的tech_class字段存储的是每个老师所教授的课程,课程之间以英文逗号分隔。现在要用语句统计每个课程对应的教师数量。语句及效果如下:

语句其实很简单,各种博客或者gpt都有不错且可行的解决方案,我们主要来理解下这段语句的执行原理,更好的学习。

part1 REGEXP_SUBSTR

关于REGEXP_SUBSTR的官方文档

具体语法这里不再赘叙,我们从单个例子入手看看效果:

REGEXP_SUBSTR可以将字段字符串根据所给正则表达式匹配并拆分(注意不是分割,但效果上等同于分割)。

最后一个参数代表要取出第几个匹配的结果:

那为什么这里要使用LEVEL?LEVEL是什么?

关于LEVEL的官方解释 具体如图:

使用之前要注意,官方文档里有句话:

To define a hierarchical relationship in a query, you must use the CONNECT BY clause.

所以关于connect by,你可以先往后看。

使用LEVEL后的效果:

LEVEL是一个在CONNECT BY子句中使用的伪列,它代表当前递归层次的级别。在每次递归调用中,LEVEL的值会增加1。在这个例子中,LEVEL的值会从1开始,一直到tech_class中逗号分隔的子串的数量------3。

为什么这样会有81条?我们的预期结果其实是3条。让我们继续探究......

Football是字段里的第一个值,只有1条;Basketball是字段里的第二个值,有10条;PingPang是字段里的第三个值,有70条!貌似越往后数据重复越多,而且次数增长的可怕,但很难发现出有什么规律。检索后基本确定出现重复数据是因为在递归过程中,regexp_substr函数没有正确移动到下一个匹配项,而是重复移动到了Basketball或者PingPang,至于它底层是什么重复移动的,额我也没搞明白....。

对此我们需要添加prior确保每次递归时都能正确提取。

part3 prior

关于prior的简单介绍

connect by中加prior可以限定父子的对应关系,限定递归路径。这里对同条记录进行递归:

加sys_guid()是为了保证层次查询,存在循环时,不出现无限递归。它为每行生成一个唯一标识,从而避免无限循环。

Part3 connect by

CONNECT BY的官方文档--分级查询

connect by常常结合prior一起实现父级查询。因此connect by LEVEL prior一般都一起出现。

附

最后再次附上针对原始的业务需求的完整的语句及输出:

复制代码
select
regexp_substr(tech_class, '[^,]+', 1, LEVEL) as class_name,
tech_name
from teacher
CONNECT BY LEVEL <= REGEXP_COUNT(tech_class, '[^,]+')
and prior tech_class = tech_class
and prior sys_guid() is not null
order by class_name
相关推荐
倔强的石头_4 小时前
聊聊金仓KFS:一款把数据同步软件做扎实的产品
数据库
闲云野鹤在人间4 小时前
MySQL|从理论、安装、备份到主从复制、MHA高可用详解
linux·运维·数据库·mysql·云计算
禾小西4 小时前
Redis:从两大维度和三大主线建立知识体系
数据库·redis·缓存
禾小西5 小时前
Redis 数据结构:快速的 Redis 有哪些慢操作?
数据结构·数据库·redis
数据库小学妹5 小时前
数据共享交换平台选型:交换方式对比与避坑指南
数据库·信创·数据同步·数据交换平台·政务数据共享·数据共享交换平台·数据库底座
loong_XL7 小时前
决策模型做内容安全检测:从踩坑到上线
数据库·安全·jev·决策模型
这个DBA有点耶7 小时前
数据库双轨并行实战:全量并行策略、增量延迟控制、双向回切与一致性校验
数据库·架构·dba
adinnet20267 小时前
保单、赔付与渠道问数:保险经营数据如何实现按需查询
大数据·数据库·人工智能
云贝贝贝8 小时前
PostgreSQL 分区表:从设计到运维,大表不再卡
运维·数据库·postgresql
oradh8 小时前
Oracle固定执行计划的方法---SQL Plan Baseline
数据库·sql·oracle