Mysql递归查询子级&添加序号&从子级ID查询所有父级

1、建表及插入数据


DROP TABLE IF EXISTS `merchant_region`;
CREATE TABLE `merchant_region`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `parent_id` int(11) NULL DEFAULT NULL,
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

INSERT INTO `merchant_region` VALUES (1, 0, '1');
INSERT INTO `merchant_region` VALUES (2, 0, '2');
INSERT INTO `merchant_region` VALUES (3, 0, '3');
INSERT INTO `merchant_region` VALUES (4, 1, '1-1');
INSERT INTO `merchant_region` VALUES (5, 4, '1-1-1');
INSERT INTO `merchant_region` VALUES (6, 4, '1-1-2');
INSERT INTO `merchant_region` VALUES (7, 6, '1-1-2-1');
INSERT INTO `merchant_region` VALUES (8, 2, '2-1');
INSERT INTO `merchant_region` VALUES (9, 2, '2-2');
INSERT INTO `merchant_region` VALUES (10, 3, '3-1');
INSERT INTO `merchant_region` VALUES (11, 1, '1-2');
INSERT INTO `merchant_region` VALUES (12, 11, '1-2-1');

Mysql递归查询子级&添加序号&从子级ID查询所有父级_第1张图片

2、 递归查询子级(包括or不包括自己)

递归查询子级sql

示例sql


select  * from merchant_region;

-- 发现使用字符型和使用数字类型查询结果在显示上不一致,所以需要转
select @ids;
select @ids:= 0;
select @ids:= '0';
select @ids:= cast(0 as char);

-- 核心(作最坏的打算->假设表中数据所代表的每一个节点都是上一个节点的子节点)
select @ids as _ids,
(
	select @ids:=group_concat(mr.id)
	from merchant_region mr
	where find_in_set(mr.parent_id,@ids)
)
from merchant_region

-- 为了更好的理解上面这个逻辑,可以执行如下的sql帮助理解
select @ids := null;
	
select @ids := if(@ids is null,1,@ids:=@ids+1) ,mr.* from merchant_region mr


-- 最终写法
select 
	mr.* 
from 
	merchant_region mr 
	inner join (select @ids:= cast(0 as char)) t1 -- 将@ids初始化,并且将数字转为字符类型
	inner join (
		select @ids as _ids1,
		(
			select @ids:=group_concat(mr.id)
			from merchant_region mr
			where find_in_set(mr.parent_id,@ids)
		) as _ids2
		from merchant_region
		where @ids is not null -- 排除掉后面都是null的数据行
	) t2
where 
	find_in_set(mr.id,t2._ids1) -- 这里选择_ids1或_ids2来决定是否包含自身

-- 使用示例
<select id="selectHierarchyRegion" resultType="com.anbao.ambientMonitor.data.dto.region.MerchantRegionCustomPropertyDTO">
    SELECT
        mr.id,
        mr.region_name AS label,
        mr.parent_id,
        mr.region_remark,
        mur.merchant_sub_user_id
    FROM
        merchant_user_region mur
        LEFT JOIN merchant_region mr ON mr.id = mur.merchant_region_id
       ,(SELECT @ids := 0) b
       ,(SELECT @ids AS _ids,(SELECT	@ids := GROUP_CONCAT(id) FROM merchant_region	WHERE	FIND_IN_SET(parent_id, @ids)) AS cids FROM merchant_region WHERE @ids IS NOT NULL ) a
    WHERE
        mur.merchant_sub_user_id = #{merchantUserId}
      AND FIND_IN_SET(mur.merchant_region_id,a._ids)
      AND mr.merchant_id = #{merchantId}
      AND mr.region_classify = 1
      AND mr.is_del = 0
    ORDER BY CONVERT(mr.region_name USING gbk)
</select>

可能存在的问题

有时候,上面这条sql查询,每次查询的结果有不一致的情况,原因不明。但须执行下面这条代码,就可以解决,不知道为什么

baseMapper.removeCache(1L)
<update id="removeCache">
      SELECT
          	@ids AS _ids,
			(
				SELECT
					@ids := GROUP_CONCAT(id)
				FROM
					merchant_region
				WHERE
					FIND_IN_SET(parent_id, @ids)
			) AS cids
      FROM
          merchant_region,
          (SELECT @ids := #{regionId}) b
      WHERE
          @ids IS NOT NULL
  </update>

处理这个存在的问题

上面查询,有的时候查出的来的结果不一致,可以先把后面的查询先查出来作为临时表,再使用Left JOIN连接起来,下面的CAST是因为单独查询这个临时表,也有点问题。

SELECT
		d.id,
		d.name,
		d.parent_id
FROM
		dept d
		LEFT JOIN(
			SELECT * FROM (
				(SELECT @ids := CAST(#{parentId} AS char)) a
				, (SELECT @ids AS _ids ,
						  (SELECT @ids := GROUP_CONCAT(id) FROM dept WHERE FIND_IN_SET(parent_id, @ids)) AS cids
				   FROM
					  	dept
				   WHERE
						@ids IS NOT NULL
				) b
			)
		) T ON FIND_IN_SET(d.id, T._ids)
WHERE
		d.hospital_area_id = #{hospitalAreaId}
		AND d.is_del = 0
ORDER BY
		d.sort_index DESC
		

可借鉴参考:

mysql根据父节点递归查询所有子节点
根据一个父节点查询所有子节点(包含自身)

SELECT au.id 
FROM (SELECT * FROM t_app_user WHERE parent_id IS NOT NULL) au,
     (SELECT @pid := '1') pd 
WHERE FIND_IN_SET(parent_id, @pid) > 0 
  AND @pid := concat(@pid, ',', id)
union select id from t_app_user where id = '1';

根据多个父节点查询所有子节点(包含自身)

SELECT au.id 
FROM (SELECT * FROM t_app_user WHERE parent_id IS NOT NULL) au,
     (SELECT @pid := '1,4') pd 
WHERE FIND_IN_SET(parent_id, @pid) > 0 
  AND @pid := concat(@pid, ',', id) 
union select id from t_app_user where FIND_IN_SET(id,@pid) > 0;

MYSQL根据id递归向下查询所有子级

SELECT
	ID.LEVEL,
	DATA.* 
FROM
	(
	SELECT
		@ids AS _ids,
		( SELECT @ids := GROUP_CONCAT( id ) FROM 表名 WHERE FIND_IN_SET( 父级 id字段, @ids ) ) AS cids,
		@l := @l + 1 AS LEVEL 
	FROM
		表名,
		( SELECT @ids := '条件id', @l := 0 ) b 
	WHERE
		@ids IS NOT NULL 
	) ID,
	表名 DATA 
WHERE
	FIND_IN_SET( DATA.id, ID._ids ) 
ORDER BY
	LEVEL,
	id

示例:

    <select id="selectAllSubDeptByDeptIds" resultType="long">
        SELECT
            d.id
        FROM
            dept d
            INNER JOIN(
                SELECT * FROM (
                    (SELECT @ids :=
                            '${@org.springframework.util.StringUtils@collectionToCommaDelimitedString(deptIdList)}'
                    ) a
                    , (SELECT @ids AS _ids ,
                              (SELECT @ids := GROUP_CONCAT(id) FROM dept WHERE FIND_IN_SET(parent_id, @ids)) AS cids
                       FROM
                            dept d
                       WHERE
                            @ids IS NOT NULL AND d.is_del = 0
                    ) b
                )
            ) T ON FIND_IN_SET(d.id, T.cids)
        WHERE
            d.is_del = 0
    </select>

示例

<delete id="deleteCourseInvitationSubDepts">
   DELETE
   FROM
       course_invitation ci
   WHERE
       ci.course_id = #{courseId}
       AND FIND_IN_SET (ci.dept_id,
       (
           SELECT
              group_concat( cids )
           FROM (
                  ( SELECT @ids :=
                      '${@org.springframework.util.StringUtils@collectionToCommaDelimitedString(deptIdList)}'
                  ) a,
                  (SELECT
                      @ids AS _ids,
                      (SELECT
                          @ids := GROUP_CONCAT( id )
                      FROM
                          dept
                      WHERE
                          FIND_IN_SET( parent_id, @ids )
                      ) AS cids
                  FROM
                      dept
                  WHERE
                      @ids IS NOT NULL
                  ) b
                )
           )
       )
</delete>

扩展-序号

依据上面的原理,我们也可以给查出来的数据添加一个简单的序号,类似于下面这种

Mysql递归查询子级&添加序号&从子级ID查询所有父级_第2张图片

select 
	mr.*,
	t1.*,
	(@ids:=@ids+1) _ids -- 序号列
from 
	merchant_region mr 
	inner join (select @ids:= 0) t1

原理

原理篇

Mysql递归查询子级&添加序号&从子级ID查询所有父级_第3张图片

获取一组连续的天数

来源:mysql按照天统计报表,当天没有数据,填0

SELECT
    @cdate := DATE_ADD(@cdate, INTERVAL - 1 DAY) DAY
  FROM
    (SELECT
      @cdate := DATE_ADD('20171219', INTERVAL + 1 DAY)
    FROM
      order) t0
  LIMIT 7

其它可参考

mysql实现无限层次父子关系查询,并返回当前查询level层级

原文:mysql实现无限层次父子关系查询,并返回当前查询level层级

一、创建表、添加测试数据

create table CS_INTCTL_ASSESS_ITEM_GATHER
(
 id int(11) PRIMARY key auto_increment,
 assess_id   VARCHAR(36),
 assess_parent_id  VARCHAR(36),
 name        VARCHAR(256)
)

insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ( 'c46a67ffa5dc4cd990e9402dd5f21e56', '7540f5592a794ec0982bbea817d4b8ce', '一、组织结构评价(20分)');
insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ('7d77b36468e04e96a56af4f105225fac', '7540f5592a794ec0982bbea817d4b8ce', '二、经营理念与风格评价(14分)');
insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ('7540f5592a794ec0982bbea817d4b8ce', 'd24e44cbc0c34452b1da93739adfe716', '内部环境');
insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ('15f1abe4b9544f7d900f6ccec9842256', '13af09d9e8ad4da297e72e3020e290c8', '一、信贷基础管理评价(10分)');
insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ('73a60d0ed27c40718b3fd707400416af', '13af09d9e8ad4da297e72e3020e290c8', '二、评级授信评价(15分)');
insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ('13af09d9e8ad4da297e72e3020e290c8', '08c080e87e134183b239cc7409be5210', '信贷业务');
insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ('08c080e87e134183b239cc7409be5210', 'd24e44cbc0c34452b1da93739adfe716', '控制活动(55%)');
insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ('d24e44cbc0c34452b1da93739adfe716', '0', '本部评价(70%)');
insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ('c46a67ffa5dc4cd990e9402dd5f21e56', '7540f5592a794ec0982bbea817d4b8ce', '一、组织结构评价(20分)');
insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ('7d77b36468e04e96a56af4f105225fac', '7540f5592a794ec0982bbea817d4b8ce', '二、经营理念与风格评价(14分)');
insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ('7540f5592a794ec0982bbea817d4b8ce', 'd24e44cbc0c34452b1da93739adfe716', '内部环境');
insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ('15f1abe4b9544f7d900f6ccec9842256', '13af09d9e8ad4da297e72e3020e290c8', '一、信贷基础管理评价(10分)');
insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ('73a60d0ed27c40718b3fd707400416af', '13af09d9e8ad4da297e72e3020e290c8', '二、评级授信评价(15分)');
insert into cs_intctl_assess_item_gather (ASSESS_ID, ASSESS_PARENT_ID, NAME)
values ('13af09d9e8ad4da297e72e3020e290c8', '08c080e87e134183b239cc7409be5210', '信贷业务');

二、查询

1、通过普通的sql查询
查询 ASSESS_ID=0的所有子级,并返回查询的子级层级

SELECT DISTINCT
	c1.LEVEL - 1 LEVEL,
	c2.assess_id,
	c2.assess_parent_id 
FROM
	(
	SELECT
		@ids AS _ids,
		( SELECT @ids := GROUP_CONCAT( assess_id ) FROM cs_intctl_assess_item_gather WHERE FIND_IN_SET( assess_parent_id, @ids ) ) AS cids,
		@l := @l + 1 AS LEVEL 
	FROM
		cs_intctl_assess_item_gather,
		( SELECT @ids := '0', @l := 0 ) b 
	WHERE
		@ids IS NOT NULL 
	) c1,
	cs_intctl_assess_item_gather c2 
WHERE
	FIND_IN_SET( c2.assess_id, c1._ids ) 
ORDER BY
	LEVEL,
	assess_id

Mysql递归查询子级&添加序号&从子级ID查询所有父级_第4张图片
2、通过定义mysql函数实现

-- 定义mysql函数
DROP FUNCTION IF EXISTS queryChildrenInfo;DELIMITER ;;
CREATE FUNCTION queryChildrenInfo(areaId INT)
RETURNS VARCHAR(4000)
BEGIN
DECLARE sTemp VARCHAR(4000);
DECLARE sTempChd VARCHAR(4000);
SET sTemp='$';
SET sTempChd = CAST(areaId AS CHAR);

WHILE sTempChd IS NOT NULL DO
SET sTemp= CONCAT(sTemp,',',sTempChd);
SELECT GROUP_CONCAT(assess_id) INTO sTempChd FROM CS_INTCTL_ASSESS_ITEM_GATHER WHERE FIND_IN_SET(assess_parent_id,sTempChd)>0;
END WHILE;
RETURN sTemp;
END;;
DELIMITER ;

-- 调用函数
SELECT DISTINCT assess_id,assess_parent_id FROM CS_INTCTL_ASSESS_ITEM_GATHER WHERE FIND_IN_SET(assess_id,queryChildrenInfo('0'))

Oracle 递归查询

https://blog.csdn.net/qq_26542493/article/details/107754967

3、从子类ID查询所有父类

mysql中从子类ID查询所有父类(做无限分类经常用到)

参考:https://www.cnblogs.com/biehongli/p/9391757.html

Mysql递归查询子级&添加序号&从子级ID查询所有父级_第5张图片

sql

SELECT
	T2.id,T2.parent_id,T2.name,T1.lvl 
FROM
	(SELECT @r := 7, @l := 0) vars, --  “7” 可以使用 #{regionId}
	(SELECT
		@r AS _id,
		(SELECT 
			@r := parent_id
		 FROM 
			merchant_region 
		 WHERE 
			id = _id    -- 注意: 查询条件这里不要写@用户变量(试了好多,发现查询结果没什么固定的规律,这也可能是前面要写@r as _id的原因) 
		) AS parent_id,
		@l := @l + 1 AS lvl 
	 FROM
		merchant_region h 
	 WHERE
		@r != 0 
	) T1
	JOIN merchant_region T2 ON T1._id = T2.id 
ORDER BY
	T1.lvl DESC

4、使用示例

<!-- 需求:区域和组织是多对多的关系,保存在organization_region中间表中,一个组织可以对应多个区域。 -->
<!--用户可以对应多个区域(多对多),保存在用户和区域的中间表merchant_user_region,区域之间存在层级关系 -->
<select id="selectRegionIdByOrganizationId" resultType="java.lang.Long">
	 SELECT
	     orr.region_id
	 FROM
	     organization_region orr
	         INNER JOIN (
	         SELECT
	             mr.id
	         FROM
	             (SELECT @ids := 0) b,
	             (
	                 SELECT
	                     @ids AS _ids,
	                     (SELECT @ids := GROUP_CONCAT(id) 
	                      FROM merchant_region 
	                      WHERE FIND_IN_SET(parent_id, @ids)
	                     ) AS cids
	                 FROM 
	                 	merchant_region
	                 WHERE
	                     @ids IS NOT NULL) c1,
	             merchant_region mr
	             LEFT JOIN merchant_user_region mur ON mr.id = mur.merchant_region_id
	         where
	             FIND_IN_SET(mr.id, c1._ids)
	           AND mr.is_del = 0
	           AND mur.merchant_sub_user_id = #{merchantSubUserId}
	         ORDER BY mr.create_time DESC) mr ON mr.id = orr.region_id
	 WHERE
	     orr.organization_id = #{id}
</select>

–补充: 根据中间关系表筛选具有权限的数据

<select id="queryList" resultType="com.anbao.ambientMonitor.data.dto.device.DeviceInfoDTO">
        SELECT
            a.*
        FROM
            (
                SELECT
                    d.id AS deviceId,
                    d.device_code,
                    d.device_model,
                    d.device_name,
                    d.online_status,
                    d.hardware_ver,
                    d.firmware_ver,
                    d.region_id,
                    d.last_communication_time,
                    d.bind_time
                FROM
                    device d
                        LEFT JOIN merchant_region mr ON d.region_id = mr.id
                        LEFT JOIN merchant_user_region mur ON mr.id = mur.merchant_region_id
                        INNER JOIN (SELECT @ids := GROUP_CONCAT(mr.id) aaaa FROM merchant_region mr WHERE mr.merchant_id = #{params.merchantId}) a
                WHERE
                    d.merchant_id = #{params.merchantId}
                  AND FIND_IN_SET(mur.merchant_region_id ,@ids)
                  AND d.is_del = 0
                  AND mur.merchant_sub_user_id = #{params.merchantSubUserId}
                  AND d.device_model = #{params.deviceModel}
                UNION ALL
                SELECT
                    d.id AS deviceId,
                    d.device_code,
                    d.device_model,
                    d.device_name,
                    d.online_status,
                    d.hardware_ver,
                    d.firmware_ver,
                    d.region_id,
                    d.last_communication_time,
                    d.bind_time
                FROM
                    device d
                WHERE
                    d.merchant_id = #{params.merchantId}
                  AND d.is_del = 0
                  AND d.device_model = #{params.deviceModel}
                  AND d.region_id IS NULL
            ) a
        ORDER BY
            a.bind_time DESC
    </select>

你可能感兴趣的:(Dao,mysql)