2009-03-18 22 views
9

Son zamanlarda Nested Set Model ürününü kullanıyorum. Hemen hemen her yararlı işlem ve görünüm için tasarım sorgulamalarından keyif aldım. Üzerine takıldığım bir şey, bir düğümünden hemen çocukların (ve sadece çocukların, daha fazla torun değil!) Nasıl seçileceğidir.Düğümün çocuklarını sorgulamanın basit bir yolu var mı?

Dürüst olmak gerekirse, bir yol biliyorum - ancak yönetilemez SQL miktarları içerir. Eminim daha basit bir çözüm var.

cevap

9

Gönderdiğiniz makaleyi okudunuz mu? Ben tabloda "parent_id" gömmek - O ne (bu hile) yaparım bitişiklik listeleri ile iç içe set kombine olan, başlığı Ancak

SELECT node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth 
FROM nested_category AS node, 
    nested_category AS parent, 
    nested_category AS sub_parent, 
    (
     SELECT node.name, (COUNT(parent.name) - 1) AS depth 
     FROM nested_category AS node, 
     nested_category AS parent 
     WHERE node.lft BETWEEN parent.lft AND parent.rgt 
     AND node.name = 'PORTABLE ELECTRONICS' 
     GROUP BY node.name 
     ORDER BY node.lft 
    )AS sub_tree 
WHERE node.lft BETWEEN parent.lft AND parent.rgt 
    AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt 
    AND sub_parent.name = sub_tree.name 
GROUP BY node.name 
HAVING depth <= 1 
ORDER BY node.lft; 

"Bir düğüm Derhal astlarına bul" altında bu yüzden bir düğümün çocuklarını kolayca sorabilirim.

+0

"... Ben ... bitişiklik listeleri ile iç içe set kombine" Ha! Ben de öyle yapıyorum. Ben bir katılıyorum Joe Celko tarafından yapılan bir sorguya göre liste görünümü. Çok fazla kod gibi görünüyor. Bağlantılı makalenin çözümü bile ... verbose. – Metaphile

+0

Yani, bir düğümün torunlarını seçerek karşılaştırın: SELECT * FROM düğümleri WHERE nodes.leftBound parentLeftBound VE parentRightBound ARASINDA; – Metaphile

+0

Eh, "child_view" oldukça basit, SELECT * FROM düğümleri WHERE parent_id = 123456: D –

7

Bana göre bu alt sorgular veya ana sütun yedeklemesi olmadan kolayca yapılabilir olmalı! Örneğin, verilen ebeveynin sol ve sağ zaten bilinmektedir:

olduğunu
SELECT child.id 
FROM nodes AS child 
LEFT JOIN nodes AS ancestor ON 
    ancestor.left BETWEEN @parentleft+1 AND @parentright-1 AND 
    child.left BETWEEN ancestor.left+1 AND ancestor.right-1 
WHERE 
    child.left BETWEEN @parentleft+1 AND @parentright-1 AND 
    ancestor.id IS NULL 

, “Söz konusu düğümün tüm soyundan gelen, kendileri ve düğüm arasında hiçbir atası ile olanları seçmek”.

+0

Performansta hangi cevabın daha iyi olduğunu merak ediyorum, bu ya da kabul edilen gönderi. Ancak, her iki çözüm de işe yarıyor. Bu biraz daha kompakt görünüyor. – andreas

+0

Çok büyük ağaçlar için, bunu MySQL'de kötü performans gösterdiğini ve SQL sunucusunda daha da kötüye gittiğini gördük çünkü veritabanı üzerinde gerçekleştirilecek yuvalanmış bir döngü gerekiyor. Kodumuzu, tüm soyluları geri almak için değiştirdik ve ardından uygulama kodumuzdaki çocuklara dayandı. – user393274

+0

@andreas Bu, kabul edilen cevaba çok benziyor, fark şu ki, çocuk sayma ve 1 çocuğa sahip olanlara filtreleme, atası NULL olup olmadığını görerek filtreliyor. Bu, daha az işi olduğu anlamına geliyor. adım adım). Daha hızlı olmalı, ama ben test etmedim. – Ariel

5

BU BİR DAHA İYİ VE

Kullanıcı "bobince" neredeyse vardı küçüktür. Bunu anladım ve benim için çalışmasını sağladım çünkü en çok MySQL deneyimim var. Ancak, bobince'nin cevabının neden insanları korkutabileceğini görebiliyorum. Sorgusu eksik. İlk önce mysql değişkenlerine parent_left ve parent_right öğesini seçmeniz gerekir.

altında iki sorgular tablo sağ sütun rgt adlı ve birincil anahtar id adında olduğu, sol kolon lft adlı, tree adlı varsayalım. Bu değerleri ihtiyaçlarınıza göre değiştirin. Ayrıca, ilk seçim ifadesini inceleyin. Görüyorsunuz ki, düğümün 5. soyundan gelenleri araştırıyorum. İstediğiniz düğümün çocuklarını aramak için 5 sayısını değiştirin.

Kişisel olarak bunun, şimdiye kadar sunulan diğerlerinden daha şık, daha seksi ve daha verimli bir sorgu olduğunu düşünüyorum.

SELECT `lft`, `rgt` INTO @parent_left, @parent_right FROM efm_files WHERE `id` = 5; 
SELECT `child`.`id` 
FROM `tree` AS `child` 
LEFT JOIN `tree` AS `ancestor` ON 
    `ancestor`.`lft` BETWEEN @parent_left+1 AND @parent_right-1 AND 
    `child`.`lft` BETWEEN `ancestor`.`lft`+1 AND `ancestor`.`rgt`-1 
WHERE 
    `child`.`lft` BETWEEN @parent_left+1 AND @parent_right-1 AND 
    `ancestor`.`id` IS NULL 
+0

Efm_files nedir? – Madbreaks

+0

efm_files, mysql veritabanımdaki bir tablonun adıdır. Veritabanınız için kendi tablo adınızla değiştirin. – mrbinky3000

0

i necro yazı, yapıyor im biliyorum ama buradaki benim görüşüm.

İç içe geçmiş kümenizde neden bir "derinlik" sütunu bulunmuyor? derinlik sütunu, bir öğenin "seviyesini" gösterecektir. böylece

, sadece çok,

select c.*
from tree as p
join tree as c on (c.left > p.left and c.right < p.right and c.depth = p.dept + 1) where p.id = @parentID

+0

Kesinlikle konuşmamak içten bir kümedir, bu hiyerarşik modellerin birleşimidir. Daha sık olmamakla birlikte, problemi çözmek için modeli değiştirmek bir seçenek değildir. – Madbreaks

0

Bir derinlik sütun ile gitmek istiyorum yapmak, bir öğenin hemen çocuk herkesin seçin. Ama Wikipedia link seçilen cevap ile birlikte cevabın iyi minimize sürüme sahip bulunan

SELECT Child.Node, Child.LEFT, Child.RIGHT 
FROM Tree AS Child, Tree AS Parent 
WHERE 
     Child.Depth = Parent.Depth + 1 
     AND Child.LEFT > Parent.LEFT 
     AND Child.RIGHT < Parent.RIGHT 
     AND Parent.LEFT = 1 -- Given Parent Node Left Index 

Wikipedia

+0

Dikkat edin, sol ve sağ ile birlikte * ek * derinlik sütunu. – Youngjae

0

kullanın.

SELECT DISTINCT Child.Name 
FROM ModelTable AS Child, ModelTable AS Parent 
WHERE Parent.Lft < Child.Lft AND Parent.Rgt > Child.Rgt -- associate Child Nodes with ancestors 
GROUP BY Child.Name 
HAVING MAX(Parent.Lft) = @parentId -- Subset for those with the given Parent Node as the nearest ancestor 

Ve Sizden Linq ile bunu ifade deneyin bağlantıyı takip edin: https://stackoverflow.com/a/25594386/361100

İlgili konular