MySQL: Ağaç Hiyerarşik sorgusu


20

MySQL'de AĞAÇ İLE ALT AĞAÇ

MYSQL'de Database COMPANY, Table: Employeeözyinelemeli bir birliktelik var , bir çalışan diğer çalışanın patronu olabilir. A self relationship of kind (SuperVisor (1)- SuperVisee (∞) ).

Tablo Oluşturma Sorgusu:

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;

Bir dizi tuples (Sorgu) ekledim:

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

Girilen satırlar aşağıdaki Ağaç-Hiyerarşik-İlişkisine sahiptir :

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

İlişki bulmak için bir sorgu yazdım:

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;

Ve çıktı:

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

[ SORU ]
Tam Hiyerarşik Ağaç yerine, SUB-TREEbir noktadan (seçmeli) ihtiyacım var örn .:
Girdi argümanı daha Bsonra çıktı aşağıdaki gibi olmalıdır ...

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

Lütfen bu konuda bana yardım et. Sorgu değilse, saklı yordam yardımcı olabilir.
Denedim, ama tüm çabalar işe yaramadı!



Topluluğa bu soruyu daha kolay keşfederken kullanması için bir test çerçevesi sağladım.
mellamokb

@bluefeet Evet, cevap alır almaz bu ikisinden birini kaldıracağım.
Grijesh Chauhan

1
@GrijeshChauhan size şunu sormama izin verin: Hangisini kendi görünür dalgalarınızı yapmak daha iyidir? Okyanusa çakıl atmak mı, yoksa küçük bir göle taş atmak mı? Doğrudan uzmanlara gitmek neredeyse kesinlikle size en iyi cevabı verecek ve bu tür bir soru o kadar önemlidir (gelişmiş veritabanı konuları), ağda kendi sitesini verdik. Ama nerede istediğini sormanı engellemeyeceğim, bu senin ayrıcalığın. Benim ayrıcalığım, ait olduğunu sanıyorsam başka bir siteye taşımak için oy kullanmak. : D İkimiz de bu durumda uygun gördüğümüz gibi ağı kullanıyoruz: D
jcolebrand

1
@jcolebrand: Aslında sadece benim hatamdı. Daha iyi, hızlı ve çok yanıt almak için birden fazla tarafa soru yayınlamak için kullanıyorum. It my experience Her zaman uzman taraflardan daha iyi cevap aldım . Ve bence soruyu Veritabanı Yöneticilerine taşımak daha iyi bir karardı. Her durumda, yığın akışı ve burada aktif olan insanlara çok minnettarım. Kendimi veya başka bir web'i bulmak çok zor olan birçok soruna gerçekten çözüm buldum.
Grijesh Chauhan

Yanıtlar:


5

Saklı Yordamlar kullanarak zaten bu tür bir şey ele aldım: Hiyerarşik bir alanın en üst seviyesini bulun: CTE'ler olmadan vs ile (24 Ekim 2011)

Yazıma bakarsanız, GetAncestry ve GetFamilyTree işlevlerini herhangi bir noktadan ağacı hareket ettirmek için bir model olarak kullanabilirsiniz.

GÜNCELLEME 2012-12-11 12:11 EDT

Ben baktı benim görevinden kodumu . Saklanan Fonksiyonu sizin için yazdım:

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

Aslında işe yarıyor. İşte bir örnek:

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>

Sadece bir av var. Sahip için fazladan bir satır ekledim

  • Sahibinin SSN'si 0
  • Sahibi MSSN 0 ile kendi patronu

İşte veriler

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>

Fikri anladı!
Grijesh Chauhan

Nasıl her Descendants almak için uyarlayabilirsiniz Aböyle 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

ayrıca çoklu düğümleri de ele alıyor mu? bir ebeveynin birden fazla düğüm bulunduğu veritabanımda asılı olduğu gibi
عثمان غني

3

Ne kullandığınıza Bitişiklik Listesi Modeli denir . Çok fazla sınırlaması var. Belirli bir yerdeki düğümü silmek / eklemek istediğinizde sorun yaşayacaksınız. İç içe Set Modelini kullanmanız daha iyi olur .

Bir yoktur ayrıntılı bir açıklama . Maalesef mysql.com'daki makale artık mevcut değil.


5
" Çok fazla sınırlaması var " - ancak sadece MySQL kullanırken. Neredeyse tüm DBMS, özyinelemeli sorguları destekler (MySQL, çok az şeyden biridir) ve modelin başa çıkmasını gerçekten kolaylaştırır.
a_horse_with_no_name

@a_horse_with_no_name MySQL dışında hiçbir şey kullanmadım. Bu yüzden hiç bilmiyordum. Bilgi için teşekkürler.
Shiplu Mokaddim
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.