一篇文章成为递归大神:MySQL递归查询(with recursive)

理论原理

1、MySQL with Recursive是什么?

        MySQL with Recursive是一种基于递归思想的MySQL查询方式,可以实现对数据的递归查询和处理,返回符合条件的数据。在MySQL 8.0版本中,该功能被正式引入。

2、MySQL with Recursive有什么作用?

        MySQL with Recursive的作用是基于一组初始数据,进行递归查询,返回符合条件的数据集。这种递归查询方式可以应用在很多场景下,比如对于树形结构、层级结构的数据处理,以及对数据进行分类汇总等。

3、MySQL with Recursive的使用限制?

        MySQL with Recursive的使用限制主要在于查询语句的复杂性和效率。递归查询的复杂度随着层数的增加而增加,如果递归层数过多可能会导致查询效率低下甚至出现死循环的情况。因此,在使用MySQL with Recursive时需要注意数据量大小和递归层数。

语法:、

WITH RECURSIVE cte_name (column_list) AS (SELECT initial_query_resultUNION [ALL]SELECT recursive_queryFROM cte_nameWHERE condition
)
SELECT * FROM cte_name;

2、MySQL with Recursive语法详解

WITH RECURSIVE:

        表示要使用递归查询的方式处理数据。

cte_name:

        给这个临时的递归表取个名字,可以在初始查询和递归查询中引用。

column_list:

        表示cte_name查询表中包含的列名,列名之间用逗号分隔。

initial_query_result:

        表示初始的查询结果,应该与column_list中的列名对应。

UNION:

        表示将两个查询结果集进行联合,使用UNION ALL则表示保留重复数据。

recursive_query:

        表示递归查询语句,应当与column_list中的列名对应。

condition:

        表示递归查询的终止条件,需要使用cte_name中的列进行判断。

SELECT * FROM cte_name:

        表示最终返回的查询结果集,可以通过cte_name查询表中的列名进行指定。

具体实例:(高级使用)

准备工作:

        ① 首先准备一张递归表:这里使用用户邀请记录表,A可以邀请B,B可以邀请C,C可以......依次随意邀请。

CREATE TABLE `sz_promotion_tree` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',`user_id` bigint DEFAULT NULL COMMENT '用户id',`parent_id` bigint DEFAULT NULL COMMENT '推荐者id',`create_time` datetime DEFAULT NULL COMMENT '推广时间',PRIMARY KEY (`id`),KEY `user_id` (`user_id`) USING BTREE,KEY `parent_id` (`parent_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='推广记录表';

② 随便准备一张用户表 比如

CREATE TABLE `sz_user` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',`nickname` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '昵称',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户表';

③ 造数据

INSERT INTO sz_user(id, nickname) VALUES (99, 'S');
INSERT INTO sz_user(id, nickname) VALUES (100, 'A');
INSERT INTO sz_user(id, nickname) VALUES (101, 'B');
INSERT INTO sz_user(id, nickname) VALUES (102, 'C');
INSERT INTO sz_user(id, nickname) VALUES (103, 'D');
INSERT INTO sz_user(id, nickname) VALUES (104, 'E');
INSERT INTO sz_user(id, nickname) VALUES (105, 'F');
INSERT INTO sz_user(id, nickname) VALUES (106, 'G');
INSERT INTO sz_user(id, nickname) VALUES (107, 'H');
INSERT INTO sz_user(id, nickname) VALUES (108, 'I');
INSERT INTO sz_user(id, nickname) VALUES (109, 'J');INSERT INTO sz_promotion_tree(id, user_id, parent_id, create_time) VALUES (1, 100, 99, NULL);
INSERT INTO sz_promotion_tree(id, user_id, parent_id, create_time) VALUES (2, 101, 100, NULL);
INSERT INTO sz_promotion_tree(id, user_id, parent_id, create_time) VALUES (3, 102, 100, NULL);
INSERT INTO sz_promotion_tree(id, user_id, parent_id, create_time) VALUES (4, 103, 101, NULL);
INSERT INTO sz_promotion_tree(id, user_id, parent_id, create_time) VALUES (5, 104, 101, NULL);
INSERT INTO sz_promotion_tree(id, user_id, parent_id, create_time) VALUES (6, 105, 102, NULL);
INSERT INTO sz_promotion_tree(id, user_id, parent_id, create_time) VALUES (7, 106, 102, NULL);
INSERT INTO sz_promotion_tree(id, user_id, parent_id, create_time) VALUES (8, 107, 103, NULL);
INSERT INTO sz_promotion_tree(id, user_id, parent_id, create_time) VALUES (9, 108, 103, NULL);
INSERT INTO sz_promotion_tree(id, user_id, parent_id, create_time) VALUES (10, 109, 104, NULL);

造出来一份这样结构的关系:

S邀请了A,A邀请了B、C,B邀请了D、E,D邀请了H、I,E邀请了J

问题一(类似向上递归)

比如现在查询 J109 的所有上级,并且还要查出,这些上级和 J109 的关系是几级

WITH RECURSIVE promotion_tree AS (SELECT id, user_id, parent_id, 1 AS levelFROM sz_promotion_treeWHERE user_id = 109UNION ALLSELECT pt.id, pt.user_id, pt.parent_id, pt2.level + 1FROM sz_promotion_tree ptJOIN promotion_tree pt2 ON pt.user_id = pt2.parent_idWHERE pt.parent_id IS NOT NULL
)
SELECT *
FROM promotion_tree;

查询结果:

刨析SQL

WITH RECURSIVE promotion_tree AS (SELECT id, user_id, parent_id, 1 AS levelFROM sz_promotion_treeWHERE user_id = 109UNION ALLSELECT pt.id, pt.user_id, pt.parent_id, pt2.level + 1FROM sz_promotion_tree ptJOIN promotion_tree pt2 ON pt.user_id = pt2.parent_idWHERE pt.parent_id IS NOT NULL
)
SELECT *
FROM promotion_tree;# ①首先,使用 WITH RECURSIVE 关键字声明了一个递归查询公共表表达式(CTE),命名为 promotion_tree。# ②在初始查询中,从 sz_promotion_tree 表中选择符合条件 user_id = 109 的记录,并为它们分配一个初始级别 1。这些记录作为递归查询的起始点。# ③使用 UNION ALL 运算符,将初始查询的结果与递归查询的结果连接起来。# ④在递归查询中,选择 sz_promotion_tree 表中的记录,连接到前一级的递归结果(promotion_tree),并通过条件 pt.user_id = pt2.parent_id 进行连接。这样可以构建一个向上层级递归的结构。# ⑤在递归查询的每一次迭代中,将前一级的层级 pt2.level 加上 1,并将结果作为当前级别 level。# ⑥递归查询继续迭代,直到不再满足条件 pt.parent_id IS NOT NULL,即没有上级用户时停止递归。# ⑦最后,从递归查询公共表表达式 promotion_tree 中选择所有列,并返回结果。

问题二(类似向下递归)

如果再加一张消费记录表,每个人在平台的消费都会给记录到消费记录表中,比如A,A下面有B、C,A邀请的第一级有几个人,就算几个分支,现在需要查询出A下面有多少个分支,并且,每个分支的消费额(比如B分支,包含B和B的所有子节点)有多少。

准备数据:给刚才的A-I,没人插入一条1w的购物记录

CREATE TABLE `sz_order` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',`user_id` bigint DEFAULT NULL COMMENT '用户id',`recharge_amount` decimal(10,2) DEFAULT NULL COMMENT '花费金额',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='购买记录';INSERT INTO sz_order(id, user_id, recharge_amount) VALUES (8, 99, 10000);
INSERT INTO sz_order(id, user_id, recharge_amount) VALUES (9, 100, 10000);
INSERT INTO sz_order(id, user_id, recharge_amount) VALUES (10, 101, 10000);
INSERT INTO sz_order(id, user_id, recharge_amount) VALUES (11, 102, 10000);
INSERT INTO sz_order(id, user_id, recharge_amount) VALUES (12, 103, 10000);
INSERT INTO sz_order(id, user_id, recharge_amount) VALUES (13, 104, 10000);
INSERT INTO sz_order(id, user_id, recharge_amount) VALUES (14, 105, 10000);
INSERT INTO sz_order(id, user_id, recharge_amount) VALUES (15, 106, 10000);
INSERT INTO sz_order(id, user_id, recharge_amount) VALUES (16, 107, 10000);
INSERT INTO sz_order(id, user_id, recharge_amount) VALUES (17, 108, 10000);
INSERT INTO sz_order(id, user_id, recharge_amount) VALUES (18, 109, 10000);

解决:拿A100举例,他下面俩链路,B和C,分别对应6w和3w

WITH RECURSIVE promotion_tree AS (SELECT id, user_id, parent_id, CAST(user_id AS CHAR(200)) AS chainFROM sz_promotion_treeWHERE parent_id = (SELECT user_id FROM sz_promotion_tree WHERE user_id = 100)UNION ALLSELECT pt.id, pt.user_id, pt.parent_id, CONCAT(pt2.chain, '->', pt.user_id)FROM sz_promotion_tree ptJOIN promotion_tree pt2 ON pt.parent_id = pt2.user_id
),
chain_summary AS (SELECT pt.chain, SUM(so.recharge_amount) AS total_amountFROM promotion_tree ptLEFT JOIN sz_order so ON pt.user_id = so.user_idGROUP BY pt.chain
)
SELECT pt.user_id, sum(cs.total_amount) as total_amount
FROM promotion_tree pt
left JOIN chain_summary cs ON cs.chain LIKE CONCAT(pt.chain, '%')
WHERE pt.parent_id = (SELECT user_id FROM sz_promotion_tree WHERE user_id = 100)
group by pt.user_id;

查询结果:

分析:

第一个递归的临时表promotion_tree结果:

第二个临时表chain_summary结果:

这两将两个表 使用关联查询,用chain 进行左模糊匹配来确定下级有那些,最后再通过 user_id限定和分组,即可查询每个链路的金额。

四、注意事项

1、递归的层数应该尽可能的少,过多的递归层数可能导致查询效率低下或者程序崩溃。

2、MySQL with Recursive功能在MySQL 8.0版本中才被正式引入,使用该功能建议使用该版本或者以上版本。

3、使用时需要考虑数据量的大小,如果数据量过大可能会影响递归查询的效率。

五、总结

MySQL with Recursive是一种基于递归思想的MySQL查询方式,可以实现对数据的递归查询和处理,应用广泛。在使用时需要注意递归的层数和数据量大小等因素。通过学习本文,相信大家已经对MySQL with Recursive有了深入的理解,并能够熟练运用该功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/141120.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【kubernetes】使用virtual-kubelet扩展k8s

1 何为virtual-kubelet? kubelet是k8s的agent,负责监听Pod的调度情况,并运行Pod。而virtual-kubelet不是真实跑在宿主机上的,而是一个可以跑在任何地方的进程,该进程向k8s伪装成一个真实的Node,但是实际的…

ssm+vue的教室信息管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频: ssmvue的教室信息管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构&…

驱动开发--汇总

一,【驱动相关概念】 1,什么是驱动 能够驱使硬件实现特定功能的软件代码 根据驱动程序是否依赖于系统内核将驱动分为裸机驱动和系统驱动 2,逻辑驱动和系统驱动的区别 裸机驱动:编写的驱动代码中没有进行任何内核相关API的调用…

Selenium WebUI 自动化测试框架

框架结构 框架结构 框架基于 PO 模型进行设计,将页面元素与操作进行拆分,减少页面改动时的维护成本;同时使用 xsd 自定义 xml 标签,通过解析 xml 来驱动 selenium 进行执行,减少了一定的语言学习成本。 主要功能 基于…

关于地址存放的例题

unsigned int a 0x1234; unsigned char b *(unsigned char*)&a; 上面代码大端存储和小端存储的值分别是多少? 大端存储的是把高位地址存放在低位地址处,低位存放到高位。小端是高位存放在高位,低位在低位。因为a是整型,所…

C++ list容器的实现及讲解

所需要的基础知识 对C类的基本了解 默认构造函数 操作符重载 this指针 引用 模板等知识具有一定的了解&#xff0c;阅读该文章会很轻松。 链表节点 template<class T>struct list_node{T _data;list_node<T>* _next;list_node<T>* _prev;list_node(const T&…

K8S:Pod容器中的存储方式及PV、PVC

文章目录 Pod容器中的存储方式一&#xff0e;emptyDir存储卷1.emptyDir存储卷概念2.emptyDir存储卷示例 二.hostPath存储卷1.hostPath存储卷概念2.hostPath存储卷示例 三.nfs共享存储卷1.nfs共享存储卷示例 四.PV和PVC1.PV、PVC概念2.PVC 的使用逻辑及数据流向3.storageclass插…

MySQL面试题-索引的基本原理及相关面试题

先了解一下MySQL的结构 下面我们重点讲一下存储引擎 MySQL的数据库和存储数据的目录是一一对应的&#xff0c;这些数据库的文件就保存在磁盘中对应的目录里 下面我们来看一下对应的具体数据文件 .frm是表的结构&#xff0c;不管什么样的索引都会有 .ibd代表我们现在使用的存…

基于微信小程序的房屋租赁系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言运行环境说明用户微信小程序端的主要功能有&#xff1a;户主微信小程序端的主要功能有&#xff1a;管理员的主要功能有&#xff1a;具体实现截图详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考论文…

力扣刷题-链表-两两交换链表中的节点

24.两两交换链表中的节点 给定一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后的链表。你不能只是单纯的改变节点内部的值&#xff0c;而是需要实际的进行节点交换。 解题思路 采用正常模拟的方法。 建议使用虚拟头结点&#xff0c;这样会方便很多&am…

仿制 Google Chrome 的恐龙小游戏

通过仿制 Google Chrome 的恐龙小游戏&#xff0c;我们可以掌握如下知识点&#xff1a; 灵活使用视口单位掌握绝对定位JavaScript 来操作 CSS 变量requestAnimationFrame 函数的使用无缝动画实现 页面结构 实现页面结构 通过上述的页面结构我们可以知道&#xff0c;此游戏中…

算法通关村第14关【白银】| 堆的经典问题

1.数组中的第k个最大元素 思路&#xff1a; 最直观的就是选择法&#xff0c;遍历一k次找到第k大的数之前使用快速排序的思想每次找出一个位置&#xff0c;会超时这里使用堆&#xff08;优先队列&#xff09;&#xff0c;找最大用小堆&#xff0c;找最小用大堆。 例如找第k大的…

【ArcGIS】土地利用变化分析详解(矢量篇)

土地利用变化分析详解-矢量篇 土地利用类型分类1 统计不同土地利用类型的面积/占比1.1 操作步骤Step1&#xff1a;Step2&#xff1a;计算面积Step3&#xff1a;计算占比 2 统计不同区域各类土地利用类型的面积2.1 操作步骤 3 土地利用变化转移矩阵3.1 研究思路3.2 操作步骤 4 分…

计算机毕业设计 智慧养老中心管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

3、SpringBoot_配置文件

四、配置文件 1.前言 曾经使用SpringMVC的时候是手动修改tomcat配置的端口信息&#xff0c;那现在Springboot如何修改&#xff1f;springboot有一个默认的配置文件 application.properties 2.配置文件分类 常用配置信息官方文档地址 https://docs.spring.io/spring-boot/doc…

【Vue.js】使用Element搭建登入注册界面axios中GET请求与POST请求跨域问题

一&#xff0c;ElementUI是什么&#xff1f; Element UI 是一个基于 Vue.js 的桌面端组件库&#xff0c;它提供了一套丰富的 UI 组件&#xff0c;用于构建用户界面。Element UI 的目标是提供简洁、易用、美观的组件&#xff0c;同时保持灵活性和可定制性 二&#xff0c;Element…

变量、因子、缺失值、类型转换、剔除多余变量、随机抽样、用R使用SQL、trim、na.rm=TRUE、数据标准化应用

变量&#xff1a;名义型、有序型、连续型变量 名义型&#xff1a;普通事件类型&#xff0c;如糖尿病I型和糖尿病II型。 有序型&#xff1a;有顺序的事件类型&#xff0c;如一年级、二年级和三年级。 连续型&#xff1a;表示有顺序的数量&#xff0c;如年龄。 因子&#xff1a;…

【一、虚拟机vmware安装】

安装虚拟机 下载 官方下载地址&#xff1a;https://www.vmware.com/cn.html 大概流程就是&#xff0c;最重要的事最后一步

转转闲鱼交易猫链接源码 支持二维码收款

最新仿二手闲置链接源码 后台一键生成链接&#xff0c;后台管理教程&#xff1a;解压源码&#xff0c;修改数据库config/Congig 不会可以看源码里有教程 下载程序&#xff1a;https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3

关于DatagridviewComboBox控件的若干技术问题

一&#xff1a;DatagridviewComboBox 选定索引更改时更改 DatagridviewTextBox 文本内容 private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e){if (dataGridView1.CurrentCell.ColumnIndex 1 && e.Contr…