MySQL: Kueri Tree-Hierarchical


20

SUB-TREE DALAM WILAYAH dalam MySQL

Di MYSQL saya Database COMPANY, saya memiliki Table: Employeeasosiasi rekursif, seorang karyawan dapat menjadi bos bagi karyawan lain. A self relationship of kind (SuperVisor (1)- SuperVisee (∞) ).

Permintaan Membuat Tabel:

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;

Saya telah memasukkan satu set tupel (Kueri):

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")  

Baris yang dimasukkan mengikuti Tree-Hierarch-Relationship :

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

Saya menulis kueri untuk menemukan hubungan:

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;

Dan outputnya adalah:

+------------+------------+----------+
| 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)

[ PERTANYAAN ]
Alih-alih menyelesaikan Hierarchical Tree, saya memerlukan SUB-TREEdari titik (selektif) misalnya:
Jika argumen input Bmaka output harus seperti di bawah ini ...

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

Tolong bantu saya dalam hal ini. Jika bukan permintaan, prosedur tersimpan dapat membantu.
Saya mencoba, tetapi semua upaya tidak berguna!



Saya hanya menyediakan kerangka uji bagi masyarakat untuk digunakan dalam mengeksplorasi pertanyaan ini dengan lebih mudah.
mellamokb

@bluefeet Ya, setelah saya mendapatkan jawaban, saya akan menghapus salah satu dari dua ini.
Grijesh Chauhan

1
@GrijeshChauhan izinkan saya bertanya kepada Anda: Mana yang lebih baik untuk membuat gelombang Anda sendiri yang terlihat? Untuk melempar kerikil ke laut, atau melempar batu ke kolam kecil? Langsung ke para ahli hampir pasti akan memberi Anda jawaban terbaik, dan pertanyaan semacam ini sangat penting (topik basis data lanjutan) sehingga kami telah memberikan situsnya sendiri di jaringan. Tetapi saya tidak akan menghentikan Anda untuk bertanya di mana Anda suka, itu hak prerogatif Anda. Hak prerogatif saya adalah memilih untuk memindahkannya ke situs lain jika saya pikir di situlah tempatnya. : D Kami berdua menggunakan jaringan sesuai keinginan kami dalam kasus ini: D
jcolebrand

1
@ jcolebrand: Sebenarnya itu hanya kesalahan saya. Saya biasa memposting pertanyaan dari berbagai sisi untuk mendapatkan respons yang lebih baik, cepat, dan banyak. It my experience Saya selalu mendapat jawaban yang lebih baik dari sisi ahli . Dan saya pikir itu keputusan yang lebih baik untuk memindahkan pertanyaan ke Administrator Database. Dalam semua kasus, saya sangat berterima kasih kepada stackoverflow dan orang-orang yang aktif di sini. Saya benar-benar mendapat solusi untuk banyak masalah yang sangat sulit untuk menemukan diri saya atau web lain.
Grijesh Chauhan

Jawaban:


5

Saya sudah membahas sesuatu seperti ini menggunakan Prosedur Tersimpan: Temukan tingkat tertinggi dari bidang hierarkis: dengan vs tanpa CTE (24 Okt 2011)

Jika Anda melihat di posting saya, Anda bisa menggunakan fungsi GetAncestry dan GetFamilyTree sebagai model untuk melintasi pohon dari titik mana pun.

UPDATE 2012-12-11 12:11 EDT

Saya melihat kembali kode saya dari posting saya . Saya menulis Fungsi Tersimpan untuk Anda:

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 $$

Ini benar-benar berfungsi. Berikut ini contohnya:

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>

Hanya ada satu tangkapan. Saya menambahkan satu baris tambahan untuk pemilik

  • Pemilik memiliki SSN 0
  • Pemiliknya adalah bosnya sendiri dengan MSSN 0

Ini datanya

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>

mengerti Ide!
Grijesh Chauhan

Bagaimana saya bisa beradaptasi untuk mendapatkan semua Keturunan Aseperti ini 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

apakah itu menangani multinode juga? karena tergantung di database saya di mana banyak node dari orangtua ditemukan
عثمان غني

3

Apa yang Anda gunakan disebut Adjacency List Model . Ini memiliki banyak keterbatasan. Anda akan bermasalah ketika ingin menghapus / menyisipkan simpul di tempat tertentu. Lebih baik Anda menggunakan Nested Set Model .

Ada penjelasan terperinci . Sayangnya artikel di mysql.com tidak ada lagi.


5
" Ini memiliki banyak keterbatasan " - tetapi hanya ketika menggunakan MySQL. Hampir semua DBMS mendukung kueri rekursif (MySQL adalah satu dari sedikit yang tidak) dan itu membuat modelnya sangat mudah untuk ditangani.
a_horse_with_no_name

@a_horse_with_no_name Tidak pernah menggunakan selain MySQL. Jadi saya tidak pernah tahu itu. Terima kasih untuk informasi.
Shiplu Mokaddim
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.