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

news2024/11/24 12:10:14

理论原理

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_result
    UNION [ALL]
    SELECT recursive_query
    FROM cte_name
    WHERE 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 level
  FROM sz_promotion_tree
  WHERE user_id = 109
  UNION ALL
  SELECT pt.id, pt.user_id, pt.parent_id, pt2.level + 1
  FROM sz_promotion_tree pt
  JOIN promotion_tree pt2 ON pt.user_id = pt2.parent_id
  WHERE pt.parent_id IS NOT NULL
)
SELECT *
FROM promotion_tree;

查询结果:

刨析SQL

WITH RECURSIVE promotion_tree AS (
  SELECT id, user_id, parent_id, 1 AS level
  FROM sz_promotion_tree
  WHERE user_id = 109
  UNION ALL
  SELECT pt.id, pt.user_id, pt.parent_id, pt2.level + 1
  FROM sz_promotion_tree pt
  JOIN promotion_tree pt2 ON pt.user_id = pt2.parent_id
  WHERE 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 chain
  FROM sz_promotion_tree
  WHERE parent_id = (SELECT user_id FROM sz_promotion_tree WHERE user_id = 100)
  UNION ALL
  SELECT pt.id, pt.user_id, pt.parent_id, CONCAT(pt2.chain, '->', pt.user_id)
  FROM sz_promotion_tree pt
  JOIN promotion_tree pt2 ON pt.parent_id = pt2.user_id
),
chain_summary AS (
  SELECT pt.chain, SUM(so.recharge_amount) AS total_amount
  FROM promotion_tree pt
  LEFT JOIN sz_order so ON pt.user_id = so.user_id
  GROUP 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.coloradmin.cn/o/1038046.html

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

相关文章

【100天精通Python】Day65:Python可视化_Matplotlib3D绘图mplot3d,绘制3D散点图、3D线图和3D条形图,示例+代码

1 mpl_toolkits.mplot3d 功能介绍 mpl_toolkits.mplot3d 是 Matplotlib 库中的一个子模块,用于绘制和可视化三维图形,包括三维散点图、曲面图、线图等。它提供了丰富的功能来创建和定制三维图形。以下是 mpl_toolkits.mplot3d 的主要功能和功能简介&am…

xxe攻击(XML外部实体)

1.定义 XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。 http://www.w3school.com.…

Spring学习笔记9 SpringIOC注解式开发

Spring学习笔记8 Bean的循环依赖问题_biubiubiu0706的博客-CSDN博客 注解的存在主要是为了简化XML的配置.Spring6倡导全注解式开发 回顾下 注解怎么定义,注解中的属性怎么定义 注解怎么使用 通过反射机制怎么读取注解 注解的自定义 注解的使用 通过反射机制怎么读取注解 I…

顺序表的实现和练习

杂谈: 有些数据结构(C语言实现)的教材/教程中会使用C中引用的语法,引用确实在形式上比指针简洁,这样做无非是为了避免后续对二级指针的使用。 我认为既然使用C语言实现数据结构,那么指针就不应该是门槛。…

【动手学深度学习-Pytorch版】序列到序列的学习(包含NLP常用的Mask技巧)

序言 这一节是对于“编码器-解码器”模型的实际应用,编码器和解码器架构可以使用长度可变的序列作为输入,并将其转换为固定形状的隐状态(编码器实现)。本小节将使用“fra-eng”数据集(这也是《动手学习深度学习-Pytor…

[论文分享] How to Better Utilize Code Graphs in Semantic Code Search?

How to Better Utilize Code Graphs in Semantic Code Search? [ESEC/FSE 2022] 语义代码搜索极大地促进了软件的重用,使用户能够找到与用户指定的自然语言查询高度匹配的代码片段。由于代码图(如控制流图和程序依赖图)丰富的表达能力,两种主流的研究工…

【Gradle-9】Gradle插件发布指南

1、前言 不管是在公司内部,还是开源,Gradle插件发布都是一项必备的技能,本文主要介绍本地发布和远端发布两种方式。 2、本地发布 2.1、添加依赖 在plugin>build.gradle文件中(插件的项目)先依赖一个maven发布的…

分布式搜索引擎Elasticsearch

一、Elasticsearch介绍 1.Elasticsearch产生背景 大数据量的检索NoSql: not only sql,泛指非关系型的数据库Nginx的7层负载均衡和4层负载均衡2.Elasticsearch是什么 一个基于Lucene的分布式搜索和分析引擎,一个开源的高扩展的分布式全文检索引擎 Elasticsearch使用Java开发…

零基础也能制作小说推文视频,输入文案就能制作推文短视频

小说推文视频一直是各类写手们追捧的创作方式之一,而如何制作出优质、吸引人的小说推文视频成了许多人关注的焦点。幸运的是,现在有了一款名为推文视频制作神器,让制作小说推文视频变得轻松简单。 这款小说推文视频神器的功能十分强大&#…

山西电力市场日前价格预测【2023-09-25】

日前价格预测 预测说明: 如上图所示,预测明日(2023-09-25)山西电力市场全天平均日前电价为442.30元/MWh。其中,最高日前电价为720.46元/MWh,预计出现在19: 00。最低日前电价为276.06元/MWh,预计…

AUTOSAR 多核操作系统时序监控系统设计

AUTOSAR 多核操作系统时序监控系统设计 0 引言1 AUTOSAR 介绍1.1 AUTOSAR 诞生1.3 AUTOSAR 架构 2 时序监控系统软硬件介绍2.1 硬件部分2.2 软件部分 3 时序监控系统设计3.1 监控系统整体设计3.2 监控数据获取3.3 监控数据存储3.4 监控数据处理 3.5 还原运行时序5 推动 5G工业互…

3D点云目标检测:Centerformer训练waymo数据集

一、环境准备 项目地址:centerformer 1.0、基础环境 python 3.8.0 torch 1.9.1cu111 waymo-open-dataset-tf-2-6-0 1.4.9 spconv 1.2.1 其余按照requirement.txt里安装就行 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt由于我本人是在…

uniapp、vue实现滑动拼图验证码

uniapp、vue实现滑动拼图验证码 实际开发工作中,在登陆的时候需要短信验证码,但容易引起爬虫行为,需要用到反爬虫验证码,今天介绍一下拼图验证码,解决验证码反爬虫中的滑动验证码反爬虫。滑动拼图验证码是在滑块验证码…

QLineEdit设置数据的输入范围QIntValidator和QDoubleValidator

在日常开发过程中QLineEdit作为输入框,有时要限制输入的内容,比哪,考试分数为0-100,这个时候就使用QIntValidator作为限制范围,而如何输入的是带小数的呢,那么使用QDoubleValidator可以吗,下面请…

ipad触控笔有必要买原装吗?ipad2023手写笔推荐

目前,在无纸教学、无纸办公的大背景下,电容笔得到了广泛的关注。只是,对于这两支电容笔的不同之处,不少人并不是很清楚。其实这两种电容笔都很好区分,第一种是主动电容笔,也就是我们常用的电容式屏幕&#…

安全生产一张图 安全生产三维地理信息平台

一、 建设目标 易图讯科技是一家专业从事大数据、移动互联网、物联网、三维GIS、AI系统研发,开发了三维电子沙盘、AI三维电子沙盘、WEB三维地球、移动端三维地球、数字武装三维电子沙盘、智慧动员三维电子沙盘、智慧公安三维电子沙盘、智慧安监三维电子沙盘、森林防…

vue重修003

文章目录 版权声明day03一、今日目标1.生命周期2.综合案例-小黑记账清单3.工程化开发入门4.综合案例-小兔仙首页 二、Vue生命周期三、Vue生命周期钩子四、生命周期钩子小案例1.在created中发送数据2.在mounted中获取焦点 五、案例-小黑记账清单1.需求图示:2.需求分析…

Maven项目在pom.xml里配置远程仓库

如图:作用 在项目的 pom.xml 文件中配置了 <repositories> 元素&#xff0c;Maven会优先使用项目级别的仓库配置&#xff0c;而不会查找全局设置文件中的仓库配置。换句话说&#xff0c;项目级别的配置会覆盖全局设置文件中的仓库配置。 这意味着当在项目的 pom.xml 文…

AUTOSAR 面试知识回顾

如果答不上来&#xff0c;就讲当时做了什么 1. Ethernet基础: 硬件接口&#xff1a; ECU到PHY&#xff1a; data 是MII总线&#xff0c; 寄存器控制是SMI总线【MDCMDIO两根线, half duplex】PHY输出(100BASE-T1)&#xff1a; MDI总线&#xff0c;2 wire 【T1: twisted 1 pair …

C++项目:仿muduo库实现高性能高并发服务器

文章目录 一、实现目标二、前置知识&#xff08;一&#xff09;HTTP服务器1.概念 &#xff08;二&#xff09;Reactor模型&#xff1a;1.概念2.分类&#xff08;1&#xff09;单Reactor单线程&#xff1a;单I/O多路复用业务处理。&#xff08;2&#xff09;单Reactor多线程&…