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.