SORU
10 EKİM 2008, Cuma


Bir ağaca doğru düz bir masa ayrıştırmak için en verimli/zarif yolu nedir?

Varsayalım emretti ağaç hiyerarşi saklayan düz bir tablo var:

Id   Name         ParentId   Order
 1   'Node 1'            0      10
 2   'Node 1.1'          1      10
 3   'Node 2'            0      20
 4   'Node 1.1.1'        2      10
 5   'Node 2.1'          3      10
 6   'Node 1.2'          1      20

İşte [id] Name biz burada bir diyagram. Kök düğüm 0 kurgusal.

                       [0] ROOT
                          /    \ 
              [1] Node 1          [3] Node 2
              /       \                   \
    [2] Node 1.1     [6] Node 1.2      [5] Node 2.1
          /          
 [4] Node 1.1.1

Ne minimalist yaklaşım doğru sipariş, doğru girintili bir ağaç gibi HTML veya metin) çıktı.

Varsayalım size daha fazla sadece temel veri yapılarını (diziler ve hashmaps), ebeveyn/çocuk başvurular, ORM, çerçeve, iki ellerini sadece ben garip nesneler var. Tablo rastgele erişilebilen bir sonuç kümesi olarak temsil edilir.

Kod veya düz İngilizce Pseudo Tamam, bu tamamen kavramsal bir soru.

Bonus soru: temelden iyi bir şekilde bir İLİŞKİSEL böyle bir ağaç yapısı mağazası var mı?


DÜZENLEMELER VE EKLEMELER

Bir yorumcu kök düğüm gerekli değil, zaten hiç görüntülenen olacak çünkü. (Mark Bessey'ler) soru: cevap için ParentId = 0 ifade etme kuralı budur "bu üst düzey". Sipariş sütun aynı üst düğüm sıralanmış olacak nasıl tanımlar.

"Sonuç kümesi konuştum" hashmaps (terminolojiyle kalmak) bir dizi olarak tasvir edilebilir. Verdiğim örnek zaten orada olması gerekiyordu. Bazı cevaplar ekstra mil gitmek ve ilk inşa, ama bu tamam.

Ağaç keyfi derin olabilir. Her düğüm N çocuk sahibi olabilir. Tam olarak "girdiler milyonlarca" akılda, ama bir ağaç. bir yoktu

Hata yok düğüm adlandırma benim tercihim ('1.1.1') bir şey için güvenmek Düğüm. Düğümleri eşit derecede iyi denilebilir '' veya 'Bob' hayır adlandırma yapısı ima, bu sadece okunabilir yapmak için. Frank

Siz parça parça çekin böylece benim çözümüm attılar.

CEVAP
10 EKİM 2008, Cuma


İlişkisel bir veritabanında ağaç-yapılandırılmış veri depolamak için çeşitli yollar vardır. Örnek göstermek ne iki yöntem kullanır:

  • Bitişiklik Listesi("üst" sütunu)
  • Yol Numaralandırma(sayıları noktalı adınızı sütun).

Başka bir çözüm olarak adlandırılırİç İçe Ayarlarve aynı tablo içinde saklanabilir de. Oku "Trees and Hierarchies in SQL for Smarties" Joe için bu tasarımlar hakkında daha fazla bilgi Celko.

Ben genellikle bir tasarıma tercih ederimKapatma Tablo("Bitişiklik İlişkisi") ağaç-yapılandırılmış veri depolama için aka Başka bir tablo gerektirir, ama sonra sorgulama ağaçları oldukça kolaydır.

Benim kitap SQL Antipatterns: Avoiding the Pitfalls of Database Programming sunum Models for Hierarchical Data with SQL and PHP ve Kapatılması Masa örtüsü.

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

Başka bir düğümden doğrudan bir soy olduğu Kapatma Tablo, tüm yolları saklayın. Başvuru kendisi için her düğüm için bir satır vardır. Örneğin, verileri kullanarak sorunuzu gösterdin ayarlayın:

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 bir ağaç böyle düğüm 1'den başlayarak:

SELECT f.* 
FROM FlatTable f 
  JOIN ClosureTable a ON (f.id = a.descendant_id)
WHERE a.ancestor_id = 1;

Çıktı (MySQL client) aşağıdaki gibi görünür:

 ---- 
| id |
 ---- 
|  1 | 
|  2 | 
|  4 | 
|  6 | 
 ---- 

Diğer bir deyişle, 3 ve 5 düğüm ayrı bir hiyerarşi parçası oldukları için dışlanan, düğüm 1'den azalan değil.


Ynt: yorum e-satis hemen çocuklar (ya da hemen üst) hakkında. "path_length" ClosureTable için daha kolay özellikle acil çocuk veya bir üst (ya da diğer herhangi bir mesafe) için bir sorgu yapmak için sütun. bir de ekleyebilirsiniz

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

O zaman belirli bir düğüm hemen çocukları sorgulamak için arama, bir terim ekleyebilirsiniz. Bu 1 olan torunları.

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

Re @Eşref yorum: "Nasıl bütün bir ağacın [Adı] Sıralama hakkında?"

İşte size bir örnek düğüm soyundan gelen tüm düğümleri dönmek için 1, name gibi diğer düğüm öznitelikleri ve ada göre sırala içeren FlatTable için onlara katılmak 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;

Re @yorum Nate:

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. YANİ moderatörler düzenleme onaylandı, ama geri geldim.

Düzenle ORDER BY b.path_length, f.name, emin olmak için muhtemelen üzerindeki son sorguda sıralama İLE SİPARİŞ hiyerarşi maçlar önerdi. Ama bu düzen çünkü işe yaramaz "Düğüm 1.1.1""". Düğüm 1.2 sonra

Eğer sipariş mantıklı bir şekilde hiyerarşi eşleştirmek istiyorsanız, bu mümkün, ama sadece yol uzunluğu tarafından sipariş ederek değil. Örneğin, MySQL Closure Table hierarchical database - How to pull information out in the correct order cevabım bak.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • efaustus9

    efaustus9

    16 HAZİRAN 2006
  • Glove and Boots

    Glove and Bo

    1 ŞUBAT 2007
  • Jonathan D.

    Jonathan D.

    3 Kasım 2006