Artık MySQL 8.0 özyinelemeli sorguları desteklediğine göre, tüm popüler SQL veritabanlarının standart sözdiziminde özyinelemeli sorguları desteklediğini söyleyebiliriz .
WITH RECURSIVE MyTree AS (
SELECT * FROM MyTable WHERE ParentId IS NULL
UNION ALL
SELECT m.* FROM MyTABLE AS m JOIN MyTree AS t ON m.ParentId = t.Id
)
SELECT * FROM MyTree;
2017'de Özyinelemeli Sorgu Atma sunumumda MySQL 8.0'da özyinelemeli sorguları test ettim .
Aşağıda 2008'den aldığım orijinal yanıt var:
Ağaçla yapılandırılmış verileri ilişkisel bir veritabanında depolamanın birkaç yolu vardır. Örneğinizde gösterdikleriniz iki yöntem kullanır:
- Bitişiklik Listesi ("üst" sütun) ve
- Yol Numaralandırma (ad sütununuzdaki noktalı sayılar).
Başka bir çözüm İç İçe Kümeler olarak adlandırılır ve aynı tabloda da saklanabilir. Bu tasarımlar hakkında daha fazla bilgi için Joe Celko'nun " Smarties için SQL'de Ağaçlar ve Hiyerarşiler " bölümünü okuyun .
Genellikle ağaç yapılı verileri saklamak için Kapatma Tablosu ("Bitişik İlişki" olarak da bilinir) adı verilen bir tasarımı tercih ederim . Başka bir tablo gerektirir, ancak daha sonra ağaçları sorgulamak oldukça kolaydır.
Sunumumda Kapatma Tablosunu SQL ve PHP ile Hiyerarşik Veri Modelleri ve kitabımda SQL Antipatterns: Veritabanı Programlamanın Tuzaklarından Kaçınma .
CREATE TABLE ClosureTable (
ancestor_id INT NOT NULL REFERENCES FlatTable(id),
descendant_id INT NOT NULL REFERENCES FlatTable(id),
PRIMARY KEY (ancestor_id, descendant_id)
);
Tüm yolları, bir düğümden diğerine doğrudan bir soyun bulunduğu Kapatma Tablosunda saklayın. Her düğümün kendisine başvurması için bir satır ekleyin. Örneğin, sorunuzda gösterdiğiniz veri kümesini kullanarak:
INSERT INTO ClosureTable (ancestor_id, descendant_id) VALUES
(1,1), (1,2), (1,4), (1,6),
(2,2), (2,4),
(3,3), (3,5),
(4,4),
(5,5),
(6,6);
Şimdi düğüm 1'den başlayarak şöyle bir ağaç alabilirsiniz:
SELECT f.*
FROM FlatTable f
JOIN ClosureTable a ON (f.id = a.descendant_id)
WHERE a.ancestor_id = 1;
Çıktı (MySQL istemcisinde) aşağıdaki gibi görünür:
+----+
| id |
+----+
| 1 |
| 2 |
| 4 |
| 6 |
+----+
Başka bir deyişle, düğüm 3 ve 5 hariç tutulur, çünkü bunlar düğüm 1'den inen ayrı bir hiyerarşinin parçasıdır.
Re: e-satis'ten yakın çocuklar (veya yakın ebeveyn) hakkında yorum yapın. Özellikle acil bir alt veya üst öğeyi (veya başka bir mesafeyi) sorgulamayı kolaylaştırmak için path_length
simgesine " " sütunu ekleyebilirsiniz ClosureTable
.
INSERT INTO ClosureTable (ancestor_id, descendant_id, path_length) VALUES
(1,1,0), (1,2,1), (1,4,2), (1,6,1),
(2,2,0), (2,4,1),
(3,3,0), (3,5,1),
(4,4,0),
(5,5,0),
(6,6,0);
Ardından, belirli bir düğümün hemen alt öğelerini sorgulamak için aramanızda bir terim ekleyebilirsiniz. Bunlar path_length
1 olan torunlardır .
SELECT f.*
FROM FlatTable f
JOIN ClosureTable a ON (f.id = a.descendant_id)
WHERE a.ancestor_id = 1
AND path_length = 1;
+----+
| id |
+----+
| 2 |
| 6 |
+----+
@Ashraf'tan yorum yapın: "Ağacın tamamını [ada göre] sıralamaya ne dersiniz?"
Düğüm 1'in torunları olan tüm düğümleri döndürmek, bunları gibi diğer düğüm özniteliklerini içeren FlatTable'a katılmak ve ada göre name
sıralamak için örnek bir sorgu .
SELECT f.name
FROM FlatTable f
JOIN ClosureTable a ON (f.id = a.descendant_id)
WHERE a.ancestor_id = 1
ORDER BY f.name;
@Nate adlı kişiden yorum yap:
SELECT f.name, GROUP_CONCAT(b.ancestor_id order by b.path_length desc) AS breadcrumbs
FROM FlatTable f
JOIN ClosureTable a ON (f.id = a.descendant_id)
JOIN ClosureTable b ON (b.descendant_id = a.descendant_id)
WHERE a.ancestor_id = 1
GROUP BY a.descendant_id
ORDER BY f.name
+------------+-------------+
| name | breadcrumbs |
+------------+-------------+
| Node 1 | 1 |
| Node 1.1 | 1,2 |
| Node 1.1.1 | 1,2,4 |
| Node 1.2 | 1,6 |
+------------+-------------+
Bir kullanıcı bugün bir düzenleme önerdi. SO moderatörler düzenlemeyi onayladı, ancak geri alıyorum.
Düzenleme ORDER BY b.path_length, f.name
, muhtemelen sıralamanın hiyerarşiyle eşleştiğinden emin olmak için yukarıdaki son sorgudaki ORDER BY öğesinin olması gerektiğini önerdi . Ancak bu işe yaramaz, çünkü "Düğüm 1.2" den sonra "Düğüm 1.1.1" komutunu verir.
Sıralamanın hiyerarşiyi mantıklı bir şekilde eşleştirmesini istiyorsanız, bu mümkündür, ancak yalnızca yol uzunluğuna göre sıralayarak değil. Örneğin, MySQL Kapatma Tablosu hiyerarşik veritabanına verdiğim cevaba bakın - Bilgileri doğru sırayla nasıl çıkarabilirim .