MySQL : 트리 계층 쿼리


20

MySQL의 트리 내 하위 트리

내 MYSQL에서 Database 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 |
+------------+------------+----------+   

이것 좀 도와주세요. 쿼리하지 않으면 저장 프로 시저가 도움이 될 수 있습니다.
나는 노력했지만 모든 노력은 쓸모가 없었다!



나는이 질문을 더 쉽게 탐구하는데 커뮤니티가 사용할 수있는 테스트 프레임 워크를 제공했다.
mellamokb

@bluefeet 예, 일단 답변을 받으면이 두 가지 중 하나를 제거합니다.
Grijesh Chauhan

1
@GrijeshChauhan이 질문을하겠습니다 : 눈에 보이는 파도를 만드는 것이 더 낫습니까? 자갈을 바다에 던지거나 바위를 작은 연못에 던지려면? 전문가에게 곧장가는 것은 거의 확실하게 당신에게 최선의 답변을 줄 것입니다. 그리고 이런 종류의 질문은 우리가 네트워크에서 자신의 사이트를 제공 할 정도로 중요합니다 (고급 데이터베이스 주제). 그러나 나는 당신이 당신이 원하는 곳에서 묻는 것을 멈추지 않을 것입니다. 그것은 당신의 특권입니다. 내 특권은 그것이 내가 속한 곳이라고 생각하면 다른 사이트로 옮기기 위해 투표하는 것입니다. : D 우리는이 경우에 적합하다고 생각
되는대로

1
@ jcolebrand : 사실 내 잘못이었습니다. 나는 더 빠르고, 빠르고 많은 답변을 얻기 위해 여러면에 질문을 게시하는 데 사용합니다. It my experience 나는 항상 전문가 쪽에서 더 나은 답변을 얻었다 . 그리고 질문을 데이터베이스 관리자에게 옮기는 것이 더 나은 결정이라고 생각합니다. 모든 경우에, 나는 스택 오버 플로우와 여기에 활동하는 사람들에게 매우 감사합니다. 나 자신이나 다른 웹을 찾기가 매우 어려운 많은 문제에 대한 해결책을 얻었습니다.
Grijesh Chauhan

답변:


5

이미 Stored Procedures를 사용하여 이러한 특성을 해결했습니다 .CTE가없는 vs. OCT ((24), 2011)

내 게시물을 살펴보면 GetAncestry 및 GetFamilyTree 함수를 주어진 지점에서 트리를 통과하는 모델로 사용할 수 있습니다.

업데이트 2012-12-11 12:11 EDT

나는 내 게시물 에서 내 코드를 되돌아 보았다 . 나는 당신을 위해 Stored Function을 작성했습니다.

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>

아이디어를 이해했습니다!
Grijesh Chauhan

A이와 같은 모든 후손을 얻는 방법A A/B A/B/C A/B/C/D A/B/C/E A/B/H A/B/H/G A/B/I A/B/I/J A/B/L A/F A/F/K
Smith

멀티 노드도 처리합니까? 부모의 여러 노드가 발견 된 내 데이터베이스에 걸려
عثمان غني

3

사용중인 것을 Adjacency List Model 이라고 합니다. 많은 한계가 있습니다. 특정 장소에서 노드를 삭제 / 삽입 할 때 문제가 발생합니다. 중첩 세트 모델 을 사용하는 것이 좋습니다 .

있습니다 자세한 설명은 . 불행히도 mysql.com의 기사는 더 이상 존재하지 않습니다.


5
" 많은 한계가있다 "-그러나 MySQL을 사용할 때만. 거의 모든 DBMS는 재귀 쿼리를 지원하며 (MySQL은 그렇지 않은 극소수 중 하나) 모델을 다루기가 매우 쉽습니다.
a_horse_with_no_name

@a_horse_with_no_name MySQL 이외의 다른 것을 사용한 적이 없습니다. 그래서 나는 그것을 몰랐다. 정보 주셔서 감사합니다.
Shiplu Mokaddim
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.