sql递归查询子类

平时工作中我们会遇到主从层次关系的结构数据,我们需要把数据取出来并且提现出层级就像树形结构一样,比如这样的结构:

数据库表结构如下,有个parent_id和sub_id,就是把两者的关系保存起来。

id为768的下面有769,770,771,772,780,781数据,同时这些数据下面有可能有其它的数据,我们要查出768下面的所有数据可以使用mysql的函数来获取一条数据下面的子集

CREATE FUNCTION `getMaterialBomChildList`(`input_parent_id` integer) RETURNS varchar(1000) CHARSET utf8
BEGIN  
      DECLARE sChildList VARCHAR(1000);  
      DECLARE sChildTemp VARCHAR(1000);  
      SET sChildTemp = cast(input_parent_id as CHAR);
			# 循环递归
      WHILE sChildTemp is not null DO
        IF (sChildList is not null) THEN  
          SET sChildList = concat(sChildList,',',sChildTemp);  
				ELSE  
					SET sChildList = concat(sChildTemp);  
				END IF;
  
        SELECT group_concat(sub_id) INTO sChildTemp FROM bs_material_bom where FIND_IN_SET(parent_id,sChildTemp)>0;  
      END WHILE;  
      RETURN sChildList;  
    END

这个函数的作用就是获取768下面的所有子集的id,我们使用navicat 查询这个函数

select getMaterialBomChildList(768) as subIds;

就能得到所有的子集

 我们在执行查询方法得到所有的数据

select * from bs_material_bom where FIND_IN_SET(parent_id,getMaterialBomChildList(768));

利用存储过程查询出结果

CREATE PROCEDURE `getBomlList`(IN `mid` int)
BEGIN
	#Routine body goes here...
	DROP TEMPORARY TABLE IF EXISTS bomlist;
	DROP TEMPORARY TABLE IF EXISTS bomlist_copy;
	CREATE TEMPORARY TABLE IF NOT EXISTS bomlist(
		mid INTEGER NOT NULL,
		qty INT NOT NULL DEFAULT 0,
		lct  VARCHAR(1024) NULL,
		mpath VARCHAR(1024) NULL,
		lid INTEGER NOT NULL
	);
	CREATE TEMPORARY TABLE IF NOT EXISTS bomlist_copy(
			mid INTEGER NOT NULL,
			qty INT NOT NULL DEFAULT 0,
			lct  VARCHAR(1024) NULL,
			mpath VARCHAR(1024) NULL,
			lid INTEGER NOT NULL
		);

	-- init
	SET @lid = 1;
	DELETE FROM bomlist;
	DELETE FROM bomlist_copy;
	INSERT INTO bomlist(mid, qty, lct, mpath, lid) values(mid, 1, '', mid, @lid);
	INSERT INTO bomlist_copy(mid, qty, lct, mpath, lid) values(mid, 1, '', mid, @lid);

	-- get sub mtls
	WHILE
		EXISTS (SELECT 1 FROM bomlist_copy A INNER JOIN bs_material_bom B ON A.mid = B.parent_id WHERE A.lid = @lid)
		-- 避免死循环
		AND @lid<10 	-- 简化处理
		-- AND NOT EXISTS(SELECT 1 FROM bomlist_copy C LEFT JOIN bs_material_bom D ON C.mid = D.parent_id WHERE C.lid = @lid AND B.sub_id in (SELECT mid FROM bomlist))
	DO
		-- get sub mtls
		INSERT INTO bomlist(mid, qty, lct, mpath, lid) SELECT B.sub_id, B.qty, B.location, CONCAT(A.mpath, ',', B.sub_id), (@lid+1) AS new_lid FROM bomlist_copy A INNER JOIN bs_material_bom B ON A.mid = B.parent_id WHERE A.lid = @lid;
	
		-- avoid reopen temporaty table
		INSERT INTO bomlist_copy(mid, qty, lct, mpath, lid) SELECT * FROM bomlist WHERE lid = (@lid + 1);

		-- init next level
		SET @lid = @lid + 1;
	END WHILE;	

	SELECT A.*, B.material_code, B.description
	FROM bomlist A LEFT JOIN bs_materials B ON A.mid=B.id
	ORDER BY A.mpath;
END

查询结果

call getBomlList(768);

### SQL查询的定义 子查询是指嵌套在一个外部查询中的内部查询。它可以在 `SELECT`、`INSERT`、`UPDATE` 或 `DELETE` 语句中使用,也可以作为表达式的组成部分。子查询的结果可以是一个单值、一列表或多行多列的数据集[^1]。 当子查询返回多行多列数据时,或者涉及更复杂的查询需求(如条件过滤无法通过简单的 `WHERE` 实现),可以通过将子查询放置在 `FROM` 子句中来实现复杂的需求。 --- ### SQL查询的主要使用场景 #### 场景 1: 复杂筛选条件 子查询常用于提供动态的筛选条件。例如,获取订单金额大于平均订单金额的所有客户: ```sql SELECT customer_id, order_amount FROM orders WHERE order_amount > (SELECT AVG(order_amount) FROM orders); ``` 上述例子展示了如何利用子查询计算出平均订单金额并将其应用于外层查询的条件判断中。 #### 场景 2: 数据关联分析 子查询可用于跨多个表进行数据分析。比如,找出销售额最高的产品类别及其对应的总销售金额: ```sql SELECT category_name, SUM(sales_amount) AS total_sales FROM products p JOIN ( SELECT product_id, SUM(amount) AS sales_amount FROM sales GROUP BY product_id ) s ON p.product_id = s.product_id GROUP BY category_name ORDER BY total_sales DESC; ``` 这里通过子查询先汇总每种产品的销售总额,再在外层查询中按类别分组统计。 #### 场景 3: 替代临时表功能 有时为了简化主查询逻辑,会把某些中间结果存放在子查询里代替创建物理临时表的操作。这不仅提高了效率还减少了额外资源消耗。 --- ### 结合视图优化查询过程 除了单独使用子查询之外,还可以考虑将频繁使用的复杂子查询封装成 **视图** 来提升可维护性和性能表现。例如,针对经常需要访问的商品分类体系,我们可以预先构建好相应的视图表以便后续快速调用[^2]: ```sql CREATE VIEW ProductHierarchyView AS WITH RECURSIVE CategoryTree AS ( -- 初始节点 SELECT id, parent_id, name FROM categories WHERE parent_id IS NULL UNION ALL -- 迭代展开层次结构 SELECT c.id, c.parent_id, c.name FROM categories c INNER JOIN CategoryTree ct ON c.parent_id = ct.id ) SELECT * FROM CategoryTree; -- 查询某一大类下的所有子类 SELECT * FROM ProductHierarchyView phv WHERE EXISTS( SELECT 1 FROM ProductHierarchyView root WHERE root.id = 'root_category_id' AND phv.id LIKE CONCAT(root.id, '%') ); ``` 此方法借助递归公用表表达式(CTE),能够有效解决树形结构数据遍历难题的同时保持良好的扩展能力[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值