GVKun编程网logo

mysql 递归查询 主要是对于层级关系的查询(mysql如何实现递归查询效果)

5

对于想了解mysql递归查询主要是对于层级关系的查询的读者,本文将提供新的信息,我们将详细介绍mysql如何实现递归查询效果,并且为您提供关于DB2:递归查询、JavaPhpMysql递归查询查询当前

对于想了解mysql 递归查询 主要是对于层级关系的查询的读者,本文将提供新的信息,我们将详细介绍mysql如何实现递归查询效果,并且为您提供关于DB2:递归查询、Java Php Mysql 递归查询 查询当前节点下的所有子节点 包含当前节点返回列表、JOOQ - 递归查询、mybatis:递归查询,关联查询传入多个参数的有价值信息。

本文目录一览:

mysql 递归查询 主要是对于层级关系的查询(mysql如何实现递归查询效果)

mysql 递归查询 主要是对于层级关系的查询(mysql如何实现递归查询效果)

最近遇到了一个问题,在 mysql 中如何完成节点下的所有节点或节点上的所有父节点的查询?
在 Oracle 中我们知道有一个 Hierarchical Queries 可以通过 CONNECT BY 来查询,但是,在 MySQL 中还没有对应的函数!!!

下面给出一个 function 来完成的方法

下面是 sql 脚本,想要运行的直接赋值粘贴进数据库即可。

创建表 treenodes(可以根据需要进行更改)

-- ---------------------------- 
-- Table structure for `treenodes` 
-- ---------------------------- 
DROP TABLE IF EXISTS `treenodes`; 
CREATE TABLE `treenodes` ( 
  `id` int(11) NOT NULL, 
  `nodename` varchar(20) DEFAULT NULL, 
  `pid` int(11) DEFAULT NULL, 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

  插入几条数据

-- ---------------------------- 
-- Records of treenodes 
-- ---------------------------- 
INSERT INTO `treenodes` VALUES (''1'', ''A'', ''0''); 
INSERT INTO `treenodes` VALUES (''2'', ''B'', ''1''); 
INSERT INTO `treenodes` VALUES (''3'', ''C'', ''1''); 
INSERT INTO `treenodes` VALUES (''4'', ''D'', ''2''); 
INSERT INTO `treenodes` VALUES (''5'', ''E'', ''2''); 
INSERT INTO `treenodes` VALUES (''6'', ''F'', ''3''); 
INSERT INTO `treenodes` VALUES (''7'', ''G'', ''6''); 
INSERT INTO `treenodes` VALUES (''8'', ''H'', ''0''); 
INSERT INTO `treenodes` VALUES (''9'', ''I'', ''8''); 
INSERT INTO `treenodes` VALUES (''10'', ''J'', ''8''); 
INSERT INTO `treenodes` VALUES (''11'', ''K'', ''8''); 
INSERT INTO `treenodes` VALUES (''12'', ''L'', ''9''); 
INSERT INTO `treenodes` VALUES (''13'', ''M'', ''9''); 
INSERT INTO `treenodes` VALUES (''14'', ''N'', ''12''); 
INSERT INTO `treenodes` VALUES (''15'', ''O'', ''12''); 
INSERT INTO `treenodes` VALUES (''16'', ''P'', ''15''); 
INSERT INTO `treenodes` VALUES (''17'', ''Q'', ''15'');

把下面的语句直接粘贴进命令行执行即可(注意修改传入的参数,默认 rootId,表明默认 treenodes)

根据传入 id 查询所有父节点的 id

delimiter // 
CREATE FUNCTION `getParLst`(rootId INT)
RETURNS varchar(1000) 

BEGIN
	DECLARE sTemp VARCHAR(1000);
	DECLARE sTempPar VARCHAR(1000); 
	SET sTemp = ''''; 
	SET sTempPar =rootId; 
	
	#循环递归
	WHILE sTempPar is not null DO 
		#判断是否是第一个,不加的话第一个会为空
		IF sTemp != '''' THEN
			SET sTemp = concat(sTemp,'','',sTempPar);
		ELSE
			SET sTemp = sTempPar;
		END IF;

		SET sTemp = concat(sTemp,'','',sTempPar); 
		SELECT group_concat(pid) INTO sTempPar FROM treenodes where pid<>id and FIND_IN_SET(id,sTempPar)>0; 
	END WHILE; 
	
RETURN sTemp; 
END

  

执行命令

select * from treenodes where FIND_IN_SET(id,getParList(15));

结果:

id nodename pid
8 H 0
9 I 8
12 L 9
15 O 12

 

根据传入 id 查询所有子节点的 id

delimiter // 
CREATE FUNCTION `getParLst`(rootId INT)
RETURNS varchar(1000) 

BEGIN
    DECLARE sTemp VARCHAR(1000);
    DECLARE sTempChd VARCHAR(1000);

    SET sTemp = ''$'';
    SET sTempChd =cast(rootId as CHAR);

    WHILE sTempChd is not null DO
        SET sTemp = concat(sTemp,'','',sTempChd);
        SELECT group_concat(id) INTO sTempChd FROM  treeNodes where FIND_IN_SET(pid,sTempChd)>0;
       END WHILE;
    RETURN sTemp; 
END

执行命令

select * from treenodes where FIND_IN_SET(id,getChildList(7)); 

结果:

 

id nodename pid
7 G 6

 

 

DB2:递归查询

DB2:递归查询

如何解决DB2:递归查询

需要帮助。

表:M_Objects

  1. Col: Id Child_Id
  2. Row1 M1 M2
  3. Row2 M3 M4
  4. Row3 M2 M5
  5. Row4 M5 M6

当我要求 Id M1 时,我希望在我的查询中得到这些结果,行:1,3,4。 所以对于Id,它应该寻找child-id并转到id...

  1. WITH RPL (oid,ocid) AS
  2. ( SELECT Upp.ID,Upp.CHILD_ID
  3. FROM M_ObjectsUpp
  4. WHERE Upp.ID = ''M1''
  5. UNION ALL
  6. SELECT child.ID,child.CHILD_ID
  7. FROM RPL ab,M_Objects child
  8. WHERE CHILD.child_id = ab.oid
  9. )
  10. SELECT *
  11. FROM RPL

解决方法

您是自上而下遍历,从 ID 开始,然后使用其 child_id 查找下一个 ID。因此,您必须将递归部分中的 WHERE 更改为:

  1. WITH RPL (oid,ocid) AS
  2. ( SELECT Upp.ID,Upp.CHILD_ID
  3. FROM M_Objects Upp
  4. WHERE Upp.ID = ''M1''
  5. UNION ALL
  6. SELECT child.ID,child.CHILD_ID
  7. FROM RPL ab,M_Objects child
  8. WHERE CHILD.id = ab.child_id
  9. )
  10. SELECT *
  11. FROM RPL
,

好的,谢谢! 是否可以在 first 之前定义一个条件,只在第一次调用而不是每次递归运行时调用它?

  1. SELECT Upp.ID,Upp.CHILD_ID
  2. FROM M_Objects Upp
  3. WHERE Upp.ID = ''M1''

Java Php Mysql 递归查询 查询当前节点下的所有子节点 包含当前节点返回列表

Java Php Mysql 递归查询 查询当前节点下的所有子节点 包含当前节点返回列表

递归查询

  • MySQL
    • 1. WITH RECURSIVE 语法
    • 2. 子查询
    • 3. 函数
  • JAVA 代码
    • Hutool 工具
    • 执行多次 SQL
    • 执行一次 SQL
  • PHP 代码

MySQL

1. WITH RECURSIVE 语法

使用了 MySQL 的 WITH RECURSIVE 语法。首先,它选取了当前节点作为起点,然后在递归的过程中找到了所有它的子节点。最后,它输出了所有找到的节点的标识符。
请注意将查询中的 [当前节点的 ID] 替换为你要查询的节点的 ID。

WITH RECURSIVE cte AS (
  SELECT id, parent_id
  FROM tree_table
  WHERE id = [当前节点的ID]
  UNION ALL
  SELECT t.id, t.parent_id
  FROM tree_table t
  INNER JOIN cte ON t.parent_id = cte.id
)
SELECT id FROM cte;

2. 子查询

如果你使用的 MySQL 版本不支持 WITH RECURSIVE 语法,或者你想尝试不使用 WITH RECURSIVE 的方法;
这个查询使用了两个子查询。第一个子查询选取了当前节点的 ID,并且作为递归查询的起点。第二个子查询从 tree_table 表中自联结,以查找当前节点的所有子节点。然后,使用 JOIN 操作将这些子节点与 tree_table 表中的原始记录匹配,从而得到当前节点下的所有子节点。
请注意将查询中的 [当前节点的 ID] 替换为你要查询的节点的 ID。

SELECT t1.id
FROM tree_table t1
JOIN (
  SELECT id FROM tree_table WHERE id = [当前节点的ID]
  UNION ALL
  SELECT t2.id FROM tree_table t2 JOIN tree_table t3 ON t2.parent_id = t3.id
  WHERE t3.id = [当前节点的ID]
) t4
ON t1.id = t4.id;

3. 函数

编写一个存储过程或函数来实现递归查询;将查询中的 [当前节点的 ID] 替换为你要查询的节点的 ID。

DELIMITER $$

CREATE FUNCTION get_all_children (node_id INT) RETURNS TEXT
BEGIN
  DECLARE child_ids TEXT DEFAULT '''';
  DECLARE child_id INT;
  
  SELECT GROUP_CONCAT(id) INTO child_ids FROM tree_table WHERE parent_id = node_id;
  
  IF child_ids IS NOT NULL THEN
    SET child_ids = CONCAT(child_ids, '','', get_all_children(child_id));
  END IF;
  
  RETURN child_ids;
END$$

DELIMITER ;

这个函数使用递归的方式来查询当前节点下的所有子节点。首先,它查找所有直接子节点的 ID,并使用 GROUP_CONCAT 函数将这些 ID 连接成一个逗号分隔的字符串。然后,对于每个子节点,函数递归调用自己来查找它的子节点,并将它们的 ID 也连接到返回值中。最后,函数返回一个包含当前节点下所有子节点 ID 的逗号分隔字符串。

请注意将函数中的 tree_table 和 id 和 parent_id 字段名称替换为你实际使用的表和字段名称。你可以使用以下语句来调用这个函数:

SELECT get_all_children([当前节点的ID]);

将查询中的 [当前节点的 ID] 替换为你要查询的节点的 ID。

JAVA 代码

Hutool 工具

//创建配置
	   TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
       // 自定义属性名 都要默认值的
       treeNodeConfig.setIdKey("id");
       treeNodeConfig.setNameKey("name");
       treeNodeConfig.setParentIdKey("parent_id");
       treeNodeConfig.setChildrenKey("child");
       // 最大递归深度 可以不设置
       treeNodeConfig.setDeep(3);
       /* * 形参: * list – 源数据集合 * rootId – 最顶层父id值 一般为 0 之类 * treeNodeConfig – 配置 * nodeParser – 转换器 * 返回值: List */
       // 构建树结构
       List<Tree<String>> build = TreeUtil.build(list, "0", treeNodeConfig, (treeNode, tree) -> {
   
           tree.setId(String.valueOf(treeNode.get("area_id")));
           tree.setParentId(String.valueOf(treeNode.get("parent_id")));
           tree.setName((CharSequence) treeNode.get("area_name"));
       });

执行多次 SQL

这个 Java 方法使用递归的方式来查询当前节点下的所有子节点。首先,它查询所有直接子节点的 ID。然后,对于每个子节点,方法递归调用自己来查找它的子节点。最后,方法返回一个包含当前节点下所有子节点 ID 的列表。

请注意将示例代码中的 tree_table 和 id 和 parent_id 字段名称替换为你实际使用的表和字段名称,以及将数据库连接的 URL、用户名和密码替换为你的实际连接信息。

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class TreeUtils {
   
  
  public static List<Integer> getAllChildren(int nodeId, Connection conn) throws SQLException {
   
    List<Integer> childIds = new ArrayList<>();
    
    // 查询所有直接子节点
    PreparedStatement stmt = conn.prepareStatement("SELECT id FROM tree_table WHERE parent_id = ?");
    stmt.setInt(1, nodeId);
    ResultSet rs = stmt.executeQuery();
    
    // 对于每个子节点,递归调用自己来查找它的子节点
    while (rs.next()) {
   
      int childId = rs.getInt("id");
      childIds.add(childId);
      childIds.addAll(getAllChildren(childId, conn));
    }
    
    rs.close();
    stmt.close();
    
    return childIds;
  }

  // 使用示例
  public static void main(String[] args) {
   
    Connection conn = null;
    try {
   
      // 创建数据库连接
      conn = DriverManager.getConnection("jdbc:mysql://localhost/mydatabase", "root", "password");
      
      // 查询当前节点的所有子节点
      List<Integer> childIds = getAllChildren([当前节点的ID], conn);
      
      // 输出所有子节点的ID
      System.out.println(childIds);
    } catch (SQLException e) {
   
      e.printStackTrace();
    } finally {
   
      try {
   
        if (conn != null) {
   
          conn.close();
        }
      } catch (SQLException e) {
   
        e.printStackTrace();
      }
    }
  }
}

执行一次 SQL

这个 Java 方法首先执行 SQL 语句查询所有节点,然后将结果集转换为列表。接着使用递归的方式来查询树结构。它遍历列表中的每个节点,如果节点的父 ID 等于指定的父 ID,则将该节点作为当前节点,递归查询该节点的子节点,并将子节点作为嵌套的子树添加到当前节点。最后,方法返回一个包含根节点的树结构的 Map 对象。

请注意将示例代码中的 tree_table 和 id 和 parent_id 字段名称替换为你实际使用的表和字段名称,以及将数据库连接的 URL、用户名和密码

import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TreeUtils {
   
  
  public static Map<String, Object> buildTree(List<Map<String, Object>> list, int parentId) {
   
    Map<String, Object> node = new HashMap<>();
    
    for (Map<String, Object> item : list) {
   
      int id = (int) item.get("id");
      int pid = (int) item.get("parent_id");
      
      if (pid == parentId) {
   
        // 设置当前节点的属性
        node.put("id", id);
        node.put("name", item.get("name"));
        
        // 递归查询当前节点的子节点
        List<Map<String, Object>> children = new ArrayList<>();
        for (Map<String, Object> child : list) {
   
          int childPid = (int) child.get("parent_id");
          if (childPid == id) {
   
            children.add(buildTree(list, id));
          }
        }
        
        // 如果有子节点,则将子节点添加到当前节点
        if (!children.isEmpty()) {
   
          node.put("children", children);
        }
      }
    }
    
    return node;
  }

  // 使用示例
  public static void main(String[] args) {
   
    Connection conn = null;
    try {
   
      // 创建数据库连接
      conn = DriverManager.getConnection("jdbc:mysql://localhost/mydatabase", "root", "password");
      
      // 执行SQL语句查询所有节点
      PreparedStatement stmt = conn.prepareStatement("SELECT * FROM tree_table");
      ResultSet rs = stmt.executeQuery();
      
      // 将结果集转换为列表
      List<Map<String, Object>> list = new ArrayList<>();
      while (rs.next()) {
   
        Map<String, Object> item = new HashMap<>();
        item.put("id", rs.getInt("id"));
        item.put("name", rs.getString("name"));
        item.put("parent_id", rs.getInt("parent_id"));
        list.add(item);
      }
      
      // 构建树结构
      Map<String, Object> tree = buildTree(list, 0);
      
      // 输出树结构
      System.out.println(tree);
      
      rs.close();
      stmt.close();
    } catch (SQLException e) {
   
      e.printStackTrace();
    } finally {
   
      try {
   
        if (conn != null) {
   
          conn.close();
        }
      } catch (SQLException e) {
   
        e.printStackTrace();
      }
    }
  }
}

PHP 代码

这个 PHP 函数使用递归的方式来查询当前节点下的所有子节点。首先,它查询所有直接子节点的 ID。然后,对于每个子节点,函数递归调用自己来查找它的子节点。最后,函数返回一个包含当前节点下所有子节点 ID 的数组。

请注意将示例代码中的 tree_table 和 id 和 parent_id 字段名称替换为你实际使用的表和字段名称。如果你使用的是其他语言或框架,可以根据类似的逻辑编写递归函数或方法来实现递归查询。

function get_all_children($node_id, $mysqli) {
   
  $child_ids = array();
  
  // 查询所有直接子节点
  $result = $mysqli->query("SELECT id FROM tree_table WHERE parent_id = $node_id");
  
  // 对于每个子节点,递归调用自己来查找它的子节点
  while ($row = $result->fetch_assoc()) {
   
    $child_id = $row[''id''];
    $child_ids[] = $child_id;
    $child_ids = array_merge($child_ids, get_all_children($child_id, $mysqli));
  }
  
  return $child_ids;
}

// 使用示例
$mysqli = new mysqli(''host'', ''username'', ''password'', ''database'');
$node_id = 1; // 替换为你要查询的节点的ID
$child_ids = get_all_children($node_id, $mysqli);
print_r($child_ids);

JOOQ - 递归查询

JOOQ - 递归查询

如何解决JOOQ - 递归查询

我有以下数据库结构:

文件

  • file_id
  • 文件名
  • folder_id

文件夹

  • folder_id
  • 文件夹名称
  • parent_folder_id

我正在尝试以这种方式动态构建文件路径:

查询: - 返回文件和所在文件夹。

dsl.select()
   .from( FILE)
   .join( FOLDER)
   .on( FILE.FOLDER_ID.eq( FOLDER.FOLDER_ID) )
   .fetch();

然后我用简单的 Java 获取父文件夹:

List<Folder> parentFolders= new ArrayList<>();
Long parentFolderId = record.get( FOLDER.PARENT_FOLDER_ID );
while ( parentFolderId != null )
{
    Folder parentFolder = folderService.get(parentFolderId );
    parentFolders.add( 0,parentFolder );
    parentFolderId = parentFolder.getParentFolderId();
}

输出看起来像这样:

Folder -> Folder -> Folder -> File

也许可以在这样的类中获取:

Long fileId;
String fileName;
Long fileId;
String fileName;
List<Folder> parents;

JOOQ 有没有办法做到这两步?这个想法是编写一个查询来查找父文件夹。仅使用 JOOQ 就可以做到这一点吗?

mybatis:递归查询,关联查询传入多个参数

mybatis:递归查询,关联查询传入多个参数

需求是:递归查询资源

1. 资源类 EntityBaseResource:

public final class EntityBaseResource {
  private Long resID = 0l;

  private String resName = "";

  private String urlPath = "";

  private String parentResID = "";

  private String iconClass = "fa fa-circle-o";

  private short level = 1;

  private String resType = "";

  private String permission = "";

  private String belongTo = "";

  private String isPublished = "";

  private short seq = 1;

  private String isValid = "1";

  // 子资源
  private List<EntityBaseResource> children;

  public final Long getResID() {
    return resID;
  }

  public final void setResID(Long resID) {
    this.resID = resID;
  }

  public final String getResName() {
    return resName;
  }

  public final void setResName(String resName) {
    this.resName = resName == null ? Constant.BLANK : resName.trim();
  }

  public final String getUrlPath() {
    return urlPath;
  }

  public final void setUrlPath(String urlPath) {
    this.urlPath = urlPath == null ? Constant.BLANK : urlPath.trim();
  }

  public final String getParentResID() {
    return parentResID;
  }

  public final void setParentResID(String parentResID) {
    this.parentResID = parentResID == null ? Constant.BLANK : parentResID.trim();
  }

  public final String getIconClass() {
    return iconClass;
  }

  public final void setIconClass(String iconClass) {
    this.iconClass = iconClass == null ? Constant.BLANK : iconClass.trim();
  }

//省略get/set方法


2.DAO

import java.util.List;

import org.apache.ibatis.annotations.Param;

import com.csget.entity.base.EntityBaseResource;

public interface DaoBaseResource {
    int deleteByPrimaryKey(Long resID);

    int insert(EntityBaseResource record);

    EntityBaseResource selectByPrimaryKey(Long resID);
    
    List<EntityBaseResource> selectRecursionRes(@Param("resID") Long resID, @Param("belongTo") String belongTo);

    int updateByPrimaryKey(EntityBaseResource record);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.csget.dao.base.DaoBaseResource">

    <!-- 基础属性 -->
    <resultMap id="BaseResultMap" type="com.csget.entity.base.EntityBaseResource">
        <id column="resID" jdbcType="BIGINT" property="resID" />
        <result column="resName" jdbcType="VARCHAR" property="resName" />
        <result column="urlPath" jdbcType="VARCHAR" property="urlPath" />
        <result column="parentResID" jdbcType="VARCHAR"
            property="parentResID" />
        <result column="iconClass" jdbcType="VARCHAR"
            property="iconClass" />    
        <result column="level" jdbcType="TINYINT" property="level" />
        <result column="resType" jdbcType="VARCHAR" property="resType" />
        <result column="permission" jdbcType="VARCHAR"
            property="permission" />
        <result column="seq" jdbcType="TINYINT" property="seq" />
        <result column="isValid" jdbcType="CHAR" property="isValid" />
    </resultMap>
    <!-- 递归资源,继承基础属性 -->
    <resultMap id="resAll" extends="BaseResultMap" type="com.csget.entity.base.EntityBaseResource">
        <collection property="children" ofType="resAll"
            column="{resID=resID,belongTo=belongTo}" select="selectRecursionRes" />
    </resultMap>

    <!-- 递归资源 -->
    <select id="selectRecursionRes" resultMap="resAll">
        SELECT resID, resName, urlPath, parentResID, iconClass, belongTo FROM t_base_resource
        WHERE parentResID=#{resID} and belongTo=#{belongTo} and isValid=''1'' ORDER BY seq ASC
    </select>
</mapper>

DAO 在调用时,通过注解传入参数

递归查询时多个参数参数,会自动调用查询结果中的字段值

同时递归查询,resultMap 采用的继承属性 ,这样可以避免一些不必要的查询,例如如果你只需要查询一条记录,不需要查询它下面的子集。

关于mysql 递归查询 主要是对于层级关系的查询mysql如何实现递归查询效果的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于DB2:递归查询、Java Php Mysql 递归查询 查询当前节点下的所有子节点 包含当前节点返回列表、JOOQ - 递归查询、mybatis:递归查询,关联查询传入多个参数的相关知识,请在本站寻找。

本文标签: