AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 30021
Accepted
Grijesh Chauhan
Grijesh Chauhan
Asked: 2012-12-07 07:36:41 +0800 CST2012-12-07 07:36:41 +0800 CST 2012-12-07 07:36:41 +0800 CST

MySQL:树分层查询

  • 772

MySQL 中的一棵树中的子树

在我的 MYSQLDatabase COMPANY中,我有一个Table: Employee递归关联,一个员工可以是其他员工的老板。A self relationship of kind (SuperVisor (1)- SuperVisee (∞) ).

查询创建表:

CREATE TABLE IF NOT EXISTS `Employee` (
  `SSN` varchar(64) NOT NULL,
  `Name` varchar(64) DEFAULT NULL,
  `Designation` varchar(128) NOT NULL,
  `MSSN` varchar(64) NOT NULL, 
  PRIMARY KEY (`SSN`),
  CONSTRAINT `FK_Manager_Employee`  
              FOREIGN KEY (`MSSN`) REFERENCES Employee(SSN)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

我插入了一组元组(查询):

INSERT INTO Employee VALUES 
 ("1", "A", "OWNER",  "1"),  

 ("2", "B", "BOSS",   "1"), # Employees under OWNER 
 ("3", "F", "BOSS",   "1"),

 ("4", "C", "BOSS",   "2"), # Employees under B
 ("5", "H", "BOSS",   "2"), 
 ("6", "L", "WORKER", "2"), 
 ("7", "I", "BOSS",   "2"), 
 # Remaining Leaf nodes   
 ("8", "K", "WORKER", "3"), # Employee under F     

 ("9", "J", "WORKER", "7"), # Employee under I     

 ("10","G", "WORKER", "5"), # Employee under H

 ("11","D", "WORKER", "4"), # Employee under C
 ("12","E", "WORKER", "4")  

插入的行具有以下Tree-Hierarchical-Relationship:

         A     <---ROOT-OWNER
        /|\             
       / A \        
      B     F 
    //| \    \          
   // |  \    K     
  / | |   \                     
 I  L H    C        
/     |   / \ 
J     G  D   E

我写了一个查询来查找关系:

SELECT  SUPERVISOR.name AS SuperVisor, 
        GROUP_CONCAT(SUPERVISEE.name  ORDER BY SUPERVISEE.name ) AS SuperVisee, 
        COUNT(*)  
FROM Employee AS SUPERVISOR 
  INNER JOIN Employee SUPERVISEE ON  SUPERVISOR.SSN = SUPERVISEE.MSSN 
GROUP BY SuperVisor;

输出是:

+------------+------------+----------+
| SuperVisor | SuperVisee | COUNT(*) |
+------------+------------+----------+
| A          | A,B,F      |        3 |
| B          | C,H,I,L    |        4 |
| C          | D,E        |        2 |
| F          | K          |        1 |
| H          | G          |        1 |
| I          | J          |        1 |
+------------+------------+----------+
6 rows in set (0.00 sec)

[问题]
而不是完整的层次树,我需要一个SUB-TREE点(选择性)例如:
如果输入参数是B那么输出应该如下......

+------------+------------+----------+
| SuperVisor | SuperVisee | COUNT(*) |
+------------+------------+----------+
| B          | C,H,I,L    |        4 |
| C          | D,E        |        2 |
| H          | G          |        1 |
| I          | J          |        1 |
+------------+------------+----------+   

请帮助我。如果不查询,存储过程可能会有所帮助。
我试过了,但所有的努力都是徒劳的!

mysql stored-procedures
  • 2 2 个回答
  • 68709 Views

2 个回答

  • Voted
  1. Best Answer
    RolandoMySQLDBA
    2012-12-11T12:09:38+08:002012-12-11T12:09:38+08:00

    我已经使用存储过程解决了这种性质的问题:查找分层字段的最高级别:有与没有 CTE(2011 年 10 月 24 日)

    如果您查看我的帖子,您可以使用 GetAncestry 和 GetFamilyTree 函数作为从任何给定点遍历树的模型。

    更新 2012-12-11 12:11 EDT

    我从帖子中回顾了我的代码。我为你写了存储函数:

    DELIMITER $$
    
    DROP FUNCTION IF EXISTS `cte_test`.`GetFamilyTree` $$
    CREATE FUNCTION `cte_test`.`GetFamilyTree`(GivenName varchar(64))
    RETURNS varchar(1024) CHARSET latin1
    DETERMINISTIC
    BEGIN
    
        DECLARE rv,q,queue,queue_children,queue_names VARCHAR(1024);
        DECLARE queue_length,pos INT;
        DECLARE GivenSSN,front_ssn VARCHAR(64);
    
        SET rv = '';
    
        SELECT SSN INTO GivenSSN
        FROM Employee
        WHERE name = GivenName
        AND Designation <> 'OWNER';
        IF ISNULL(GivenSSN) THEN
            RETURN ev;
        END IF;
    
        SET queue = GivenSSN;
        SET queue_length = 1;
    
        WHILE queue_length > 0 DO
            IF queue_length = 1 THEN
                SET front_ssn = queue;
                SET queue = '';
            ELSE
                SET pos = LOCATE(',',queue);
                SET front_ssn = LEFT(queue,pos - 1);
                SET q = SUBSTR(queue,pos + 1);
                SET queue = q;
            END IF;
            SET queue_length = queue_length - 1;
            SELECT IFNULL(qc,'') INTO queue_children
            FROM
            (
                SELECT GROUP_CONCAT(SSN) qc FROM Employee
                WHERE MSSN = front_ssn AND Designation <> 'OWNER'
            ) A;
            SELECT IFNULL(qc,'') INTO queue_names
            FROM
            (
                SELECT GROUP_CONCAT(name) qc FROM Employee
                WHERE MSSN = front_ssn AND Designation <> 'OWNER'
            ) A;
            IF LENGTH(queue_children) = 0 THEN
                IF LENGTH(queue) = 0 THEN
                    SET queue_length = 0;
                END IF;
            ELSE
                IF LENGTH(rv) = 0 THEN
                    SET rv = queue_names;
                ELSE
                    SET rv = CONCAT(rv,',',queue_names);
                END IF;
                IF LENGTH(queue) = 0 THEN
                    SET queue = queue_children;
                ELSE
                    SET queue = CONCAT(queue,',',queue_children);
                END IF;
                SET queue_length = LENGTH(queue) - LENGTH(REPLACE(queue,',','')) + 1;
            END IF;
        END WHILE;
    
        RETURN rv;
    
    END $$
    

    它确实有效。这是一个示例:

    mysql> SELECT name,GetFamilyTree(name) FamilyTree
        -> FROM Employee WHERE Designation <> 'OWNER';
    +------+-----------------------+
    | name | FamilyTree            |
    +------+-----------------------+
    | A    | B,F,C,H,L,I,K,D,E,G,J |
    | G    |                       |
    | D    |                       |
    | E    |                       |
    | B    | C,H,L,I,D,E,G,J       |
    | F    | K                     |
    | C    | D,E                   |
    | H    | G                     |
    | L    |                       |
    | I    | J                     |
    | K    |                       |
    | J    |                       |
    +------+-----------------------+
    12 rows in set (0.36 sec)
    
    mysql>
    

    只有一个捕获。我为所有者添加了额外的一行

    • 所有者的 SSN 为 0
    • 所有者是他自己的老板,MSSN 为 0

    这是数据

    mysql> select * from Employee;
    +-----+------+-------------+------+
    | SSN | Name | Designation | MSSN |
    +-----+------+-------------+------+
    | 0   | A    | OWNER       | 0    |
    | 1   | A    | BOSS        | 0    |
    | 10  | G    | WORKER      | 5    |
    | 11  | D    | WORKER      | 4    |
    | 12  | E    | WORKER      | 4    |
    | 2   | B    | BOSS        | 1    |
    | 3   | F    | BOSS        | 1    |
    | 4   | C    | BOSS        | 2    |
    | 5   | H    | BOSS        | 2    |
    | 6   | L    | WORKER      | 2    |
    | 7   | I    | BOSS        | 2    |
    | 8   | K    | WORKER      | 3    |
    | 9   | J    | WORKER      | 7    |
    +-----+------+-------------+------+
    13 rows in set (0.00 sec)
    
    mysql>
    
    • 5
  2. Shiplu Mokaddim
    2012-12-07T07:46:18+08:002012-12-07T07:46:18+08:00

    您使用的称为Adjacency List Model。它有很多限制。当您想在特定位置删除/插入节点时,您会遇到问题。最好使用嵌套集模型。

    有详细的解释。不幸的是,mysql.com 上的文章不再存在。

    • 3

相关问题

  • 是否有任何 MySQL 基准测试工具?[关闭]

  • 我在哪里可以找到mysql慢日志?

  • 如何优化大型数据库的 mysqldump?

  • 什么时候是使用 MariaDB 而不是 MySQL 的合适时机,为什么?

  • 组如何跟踪数据库架构更改?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何查看 Oracle 中的数据库列表?

    • 8 个回答
  • Marko Smith

    mysql innodb_buffer_pool_size 应该有多大?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    从 .frm 和 .ibd 文件恢复表?

    • 10 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve