SQL递归查询树型分类数据

目录

前言

 1.准备分类数据

 2.递归原理

 3.实现

 4.结合mybatis查询

总结


前言

相信大家在处理业务的时候经常会遇到分类数据,当面对这种情况时该如何处理呢?在这里我使用了两种方式解决:一种使用sql递归的方式,另一种是java代码方式处理(下一期)。


一、SQL递归

1.准备分类数据

代码如下(示例):

DROP TABLE IF EXISTS `course_category`;
CREATE TABLE `course_category`  (
  `id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键',
  `name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '分类名称',
  `label` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '分类标签默认和名称一样',
  `parentid` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0' COMMENT '父结点id(第一级的父节点是0,自关联字段id)',
  `is_show` tinyint NULL DEFAULT NULL COMMENT '是否显示',
  `orderby` int NULL DEFAULT NULL COMMENT '排序字段',
  `is_leaf` tinyint NULL DEFAULT NULL COMMENT '是否叶子',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '课程分类' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of course_category
-- ----------------------------

INSERT INTO `course_category` VALUES ('1-3-3', '.NET', '.NET', '1-3', 1, 3, 1);
INSERT INTO `course_category` VALUES ('1-3-4', 'Objective-C', 'Objective-C', '1-3', 1, 4, 1);
INSERT INTO `course_category` VALUES ('1-3-5', 'Go语言', 'Go语言', '1-3', 1, 5, 1);

INSERT INTO `course_category` VALUES ('1-4', '数据库', '数据库', '1', 1, 4, 0);
INSERT INTO `course_category` VALUES ('1-4-1', 'Oracle', 'Oracle', '1-4', 1, 1, 1);
INSERT INTO `course_category` VALUES ('1-4-2', 'MySQL', 'MySQL', '1-4', 1, 2, 1);
INSERT INTO `course_category` VALUES ('1-4-3', 'SQL Server', 'SQL Server', '1-4', 1, 3, 1);
INSERT INTO `course_category` VALUES ('1-4-4', 'DB2', 'DB2', '1-4', 1, 4, 1);
INSERT INTO `course_category` VALUES ('1-4-5', 'NoSQL', 'NoSQL', '1-4', 1, 5, 1);
INSERT INTO `course_category` VALUES ('1', '根结点', '根结点', '0', 1, 1, 0);
INSERT INTO `course_category` VALUES ('1-1', '前端开发', '前端开发', '1', 1, 1, 0);
INSERT INTO `course_category` VALUES ('1-1-1', 'HTML/CSS', 'HTML/CSS', '1-1', 1, 1, 1);
INSERT INTO `course_category` VALUES ('1-1-2', 'JavaScript', 'JavaScript', '1-1', 1, 2, 1);
INSERT INTO `course_category` VALUES ('1-1-3', 'jQuery', 'jQuery', '1-1', 1, 3, 1);
INSERT INTO `course_category` VALUES ('1-1-4', 'ExtJS', 'ExtJS', '1-1', 1, 4, 1);
INSERT INTO `course_category` VALUES ('1-1-5', 'AngularJS', 'AngularJS', '1-1', 1, 5, 1);

INSERT INTO `course_category` VALUES ('1-2', '移动开发', '移动开发', '1', 1, 2, 0);
INSERT INTO `course_category` VALUES ('1-2-1', '微信开发', '微信开发', '1-2', 1, 1, 1);
INSERT INTO `course_category` VALUES ('1-2-2', 'iOS', 'iOS', '1-2', 1, 2, 1);
INSERT INTO `course_category` VALUES ('1-2-3', '手游开发', '手游开发', '1-2', 1, 3, 1);
INSERT INTO `course_category` VALUES ('1-2-4', 'Swift', 'Swift', '1-2', 1, 4, 1);
INSERT INTO `course_category` VALUES ('1-2-5', 'Android', 'Android', '1-2', 1, 5, 1);

INSERT INTO `course_category` VALUES ('1-3', '编程开发', '编程开发', '1', 1, 3, 0);
INSERT INTO `course_category` VALUES ('1-3-1', 'C/C++', 'C/C++', '1-3', 1, 1, 1);
INSERT INTO `course_category` VALUES ('1-3-2', 'Java', 'Java', '1-3', 1, 2, 1);

 表图如下所示:

SQL递归查询树型分类数据_第1张图片

 2.递归原理

 要实现sql递归查询,首先要明白其原理。

递归查询原理:SQL Server中的递归查询是通过CTE(表表达式)来实现。至少包含两个子查询,第一个查询为定点成员(种子查询),种子查询只是作为一个根查询,用于递归的定位;第二个查询被称为递归查询, 这两个子查询可以通过 UNION、UNION ALL或UNION DISTINCT 连接在一起。

注意RECURSIVE 关键字只在MySQL8+版本生效。种子查询只会执行一次,并得到初始的数据作为根子集,而递归查询没有显式的递归终止条件,只有当第二个递归查询重复执行(实现递归)直到没有新的行产生,返回空结果集或是超出了递归次数的最大限制时才停止递归。最终将所有的结果集都查询出来,这对于深层查询(如具有父子关系的查询)是非常有用的。

优点:效率高,大量数据集下,速度比程序的查询快。

SQL递归的常见形式:

WITH RECURSIVE CTE AS (

SELECT column1,column2... FROM tablename WHERE conditions

UNION ALL

SELECT column1,column2... FROM tablename 

INNER JOIN CTE ON conditions 

)

3.实现

sql如下:

with recursive t1 as (
select * from course_category p where id= "1"
    union all
    select t.* from course_category t inner join t1 on t1.id = t.parentid
    )
    select * from t1 order by t1.id, t1.orderby

查询结果如下:

SQL递归查询树型分类数据_第2张图片

 4.结合mybatis查询

引入依赖如下:



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.3.12.RELEASE
         
    
    com.example
    testdemo
    0.0.1-SNAPSHOT
    testdemo
    testdemo

    
        1.8
    

    
        
            mysql
            mysql-connector-java
        
        
            org.projectlombok
            lombok
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.5.1
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        
    

    
        
            
                
                src/main/java
                
                    **/*.xml
                
            
        
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.8.1
                
                    1.8
                    1.8
                    UTF-8
                
            
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


 yml配置:

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
#  注意这里的配置 我是把mapper映射放在java目录下 才这样写的
mybatis-plus:
  mapper-locations: com/example/testdemo/dao/*.xml

目录结构如下所示:

SQL递归查询树型分类数据_第3张图片

Course实体类: 

@Data
@TableName(value = "course_category")
public class Course implements Serializable {

    @TableField(value = "id")
    private String id;

    private String name;

    private String label;

    @TableField(value = "parentid")
    private String parentId;

    @TableField(value = "is_show")
    private Integer isShow;

    private Integer orderby;

    @TableField(value = "is_leaf")
    private Integer isLeaf;

    @TableField(exist = false)
    List courseList;
}

 CourseMapper映射类:

@Mapper
public interface CourseMapper extends BaseMapper {

    List selectTreeByRootId(String id);
}

CourseMapper.xml:





    

因为返回数据并不满足分类格式,所以 最后再把数据封装进Crouse就行 ,封装操作如下:

CourseServiceImpl类:
    @Autowired
    CourseMapper courseMapper;
    @Override
    public  List selectTreeNode(String id){
        List courseList =  courseMapper.selectTreeByRootId(id);
        List categoryTreeDtos = new ArrayList<>();
        HashMap mapTemp = new HashMap<>();
        courseList.stream().forEach(item->{
            mapTemp.put(item.getId(),item);
            //只将根节点的下级节点放入list
            if(item.getParentId().equals("1")){
                categoryTreeDtos.add(item);
            }
            Course fatherCourse = mapTemp.get(item.getParentId());
            if(fatherCourse!=null){
                if(fatherCourse.getCourseList() ==null){
                    fatherCourse.setCourseList(new ArrayList());
                }
                //向节点的下级节点list加入节点
                fatherCourse.getCourseList().add(item);
            }
        });
        return categoryTreeDtos;
    }

测试:

    @Autowired
    CourseService courseService;

    @Test
    void context() {
        List courseList = courseService.selectTreeNode("1");
        System.out.println(courseList);
    }

结果如图遍成功完成:

SQL递归查询树型分类数据_第4张图片


总结

感谢大家的观看

此文章只是尝试练习递归查分类数据,新手上路,大家多多关照。

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