Ebeveyn-Çocuk Ağacı Hiyerarşik SİPARİŞ


21

SQL Server 2008 R2'deki verileri takip etmeliyim. SQLFiddle

Şema:

CREATE TABLE [dbo]. [ICFilters] (
   [ICFilterID] [int] KİMLİK (1,1) NULL DEĞİL,
   [ParentID] [int] NULL DEĞİL DEĞİL
   [FilterDesc] [varchar] (50) NULL DEĞİL,
   [Aktif] [tinyint] NULL DEĞİL DEĞİL
 CONSTRAINT [PK_ICFilters] PRIMARY KEY CLUSTERED 
 ([ICFilterID] ASC) İLE 
    PAD_INDEX = KAPALI,
    İSTATİSTİK_NORECOMPUTE = KAPALI,
    IGNORE_DUP_KEY = KAPALI,
    ALLOW_ROW_LOCKS = AÇIK,
    ALLOW_PAGE_LOCKS = AÇIK
 ) [PRIMARY] AÇIK
) [PRIMARY] AÇIK

[Dbo]. [ICFilters] INSERT [ParentID, FilterDesc, Etkin)
Değerler 
(0, 'Ürün Türü', 1),
(1, 'ProdSubType_1', 1),
(1, 'ProdSubType_2', 1),
(1, 'ProdSubType_3', 1),
(1, 'ProdSubType_4', 1),
(2 'PST_1.1', 1),
(2 'PST_1.2', 1),
(2 'PST_1.3', 1),
(2 'PST_1.4', 1),
(2 'PST_1.5', 1),
(2 'PST_1.6', 1),
(2 'PST_1.7', 0),
(3 'PST_2.1', 1),
(3 'PST_2.2', 0),
(3 'PST_2.3', 1),
(3 'PST_2.4', 1),
(14 'PST_2.2.1', 1),
(14 'PST_2.2.2', 1),
(14 'PST_2.2.3', 1),
(3 'PST_2.8', 1)

Tablo:

| ICFILTERID | PARENTİD | FİLTREÇ | AKTİF |
--------------------------------------------------
| 1 | 0 | Ürün Tipi | 1 |
| 2 | 1 | ProdSubType_1 | 1 |
| 3 | 1 | ProdSubType_2 | 1 |
| 4 | 1 | ProdSubType_3 | 1 |
| 5 | 1 | ProdSubType_4 | 1 |
| 6 | 2 | PST_1.1 | 1 |
| 7 | 2 | PST_1.2 | 1 |
| 8 | 2 | PST_1.3 | 1 |
| 9 | 2 | PST_1.4 | 1 |
| 10 | 2 | PST_1.5 | 1 |
| 11 | 2 | PST_1.6 | 1 |
| 12 | 2 | PST_1.7 | 0 |
| 13 | 3 | PST_2.1 | 1 |
| 14 | 3 | PST_2.2 | 0 |
| 15 | 3 | PST_2.3 | 1 |
| 16 | 3 | PST_2.4 | 1 |
| 17 | 14 | PST_2.2.1 | 1 |
| 18 | 14 | PST_2.2.2 | 1 |
| 19 | 14 | PST_2.2.3 | 1 |
| 20 | 3 | PST_2.8 | 1 |

Her satırın ebeveyni ve kökü vardır parentid = 0. FilterDescBen sipariş için bu ayrıştırmak için deneyin böylece ler sadece örnek açıklamalardır.

Soru

Tüm satırları ağaç benzeri bir şekilde seçmek mümkün müdür? Öyleyse nasıl? 'Ağaç benzeri' derken, tekrar tekrar ebeveynlerini seçtikten sonra bütün çocuklarını, ardından da her birinin tüm çocuklarını ve benzerlerini seçin. Derinlik ilk ağaç geçişi.

Arkadaşlarım ve ben denedik, ancak çalışma çözümlerimizde yetersiz kaldık ama denemeye devam edeceğiz. Ben sql oldukça yeni, bu yüzden belki bu kolayca yapılabilir ve ben sadece işleri zorlaştırıyorum.

Örnek (istenen) çıktı:

| ICFILTERID | PARENTİD | FİLTREÇ | AKTİF |
--------------------------------------------------
| 1 | 0 | Ürün Tipi | 1 |
| 2 | 1 | ProdSubType_1 | 1 |
| 6 | 2 | PST_1.1 | 1 |
| 7 | 2 | PST_1.2 | 1 |
| 8 | 2 | PST_1.3 | 1 |
| 9 | 2 | PST_1.4 | 1 |
| 10 | 2 | PST_1.5 | 1 |
| 11 | 2 | PST_1.6 | 1 |
| 12 | 2 | PST_1.7 | 0 |
| 3 | 1 | ProdSubType_2 | 1 |
| 13 | 3 | PST_2.1 | 1 |
| 14 | 3 | PST_2.2 | 0 |
| 17 | 14 | PST_2.2.1 | 1 |
| 18 | 14 | PST_2.2.2 | 1 |
| 19 | 14 | PST_2.2.3 | 1 |
| 15 | 3 | PST_2.3 | 1 |
| 16 | 3 | PST_2.4 | 1 |
| 20 | 3 | PST_2.8 | 1 |
| 4 | 1 | ProdSubType_3 | 1 |
| 5 | 1 | ProdSubType_4 | 1 |

CTE kullanmak en iyi olurdu
Kin Shah

1
Tablo verisi belirli bir sırada yüklenmek zorunda kalmadan istenen sonuç sıralamasını gösteren bir iş parçacığı. İstenilen sıralamayı sağlayan bir "yol" oluşturmak için row_number () ve partition komutunu kullanır. ask.sqlservercentral.com/questions/48518/…

Yanıtlar:


25

Tamam, yeterince beyin hücresi öldü.

SQL Fiddle

WITH cte AS
(
  SELECT 
    [ICFilterID], 
    [ParentID],
    [FilterDesc],
    [Active],
    CAST(0 AS varbinary(max)) AS Level
  FROM [dbo].[ICFilters]
  WHERE [ParentID] = 0
  UNION ALL
  SELECT 
    i.[ICFilterID], 
    i.[ParentID],
    i.[FilterDesc],
    i.[Active],  
    Level + CAST(i.[ICFilterID] AS varbinary(max)) AS Level
  FROM [dbo].[ICFilters] i
  INNER JOIN cte c
    ON c.[ICFilterID] = i.[ParentID]
)

SELECT 
  [ICFilterID], 
  [ParentID],
  [FilterDesc],
  [Active]
FROM cte
ORDER BY [Level];

2
Bu tam ihtiyacım olan şeydi! Bunun üzerinde çok fazla beyin hücresi öldüğünü kabul ediyorum. Ne istediğim konusunda net değildim mi? Öyleyse soruyu gelecekteki referansım için düzenleyeceğim. Olması gerektiğinden kesinlikle daha zorlaştırıyordum ...
Başmelek33

1
@ Başmelek33 Sorunu ve ihtiyacınız olanı belirlemek için iyi bir iş çıkardınız. Ayrıca, sqlfiddle gerçekten yardımcı olur.
Travis

2
+1 ancak sıralama için [ICFilterID] [int] IDENTITY (1,1) kullanımı yalnızca çalışır; öğeler doğru sırayla eklenir, ancak sıralama için başka bir alan henüz OT
bummi

4
Bunun% 100 doğru bir çözüm olduğuna inanmıyorum. Bütün sıraları hiyerarşideki doğru seviyeleri ile listelemek zor olsa da, soruyu sorduğu sıraya göre listelemez. Sorulara göre sıraları doğru sıraya koymak mümkün mü? Ben de onu arıyorum.

1
Bu, sorumu [FilterDesc]sütununda verilen veriler kurgusal olduğu ve bu sırasın gereksiz / önemsiz olduğu için yanıtlıyor . @Travis Gan yanıtında mantık ardından bu sıralamayı elde etmek için yapması gereken tek bir başka eklemektir CASTiçin Level. Örneğin. Level + CAST( CAST(i.[ICFilterID] AS varbinary(max)) AS LevelOlur Level + CAST(i.[FilterDesc] AS varbinary(max)) + CAST(i.[ICFilterID] AS varbinary(max)) AS Level.
Başmelek33

1

Yukarıdakiler benim için doğru çalışmıyor. Facebook tipinde bir veri içeren 2 masa kurulumunu hayal edin. Tablo 1, PostId + 'da diğer alanlara sahiptir. PostId otomatik artıştır ve açık bir şekilde arayüzünüzde, DESC'yi en son yazının başında olacak şekilde sıralarsınız.

Şimdi yorum tablosu için. Tablo 2 Bu tablo CommentId birincil anahtar, otomatik sayıdır. GUI'nizde ASC'yi görüntülemek istersiniz, böylece ipliği okurken anlamlı olur. (en eski (en küçük sayı)) Tablo 2'deki diğer önemli anahtarlar şunlardır: PostId (FK gönderilere geri dön) ve ParentId (FK - CommentId), burada ParentId, NULL olacaktır. Birisi bir yorumda REPLY olursa, parentId, commentid ile doldurulur.
Umarım drifti alırsınız. CTE şöyle görünecek:

WITH  Comments
        AS ( SELECT  CommentId , ParentId, CAST(CommentId AS VARBINARY(MAX)) AS Sortkey, 0 AS Indent
             FROM    dbo.Comments
             WHERE   ParentId IS NULL AND PostId = 105
             UNION ALL
             SELECT  b.CommentId , b.ParentId,  c.Sortkey + CAST(b.CommentId AS varbinary(max))  AS Sortkey, c.Indent + 1 AS Indent
             FROM    dbo.Comments b
             INNER JOIN Comments c ON c.CommentId = b.ParentId
           )
   SELECT   *
   FROM     Comments
   ORDER BY Sortkey

Örnek çıktı

1   NULL    0x0000000000000001  0
5   1   0x00000000000000010000000000000001  1
6   5   0x000000000000000100000000000000010000000000000005  2
2   NULL    0x0000000000000002  0

105 F / B gönderiminde, iki yorum yapıldı (CommentIds 1 ve 2) Biri daha sonra Comment1'e (CommentId 5, ParentId 1) cevap verdi ve sonra başka biri bu cevaba yorum yaptı, böylece Comment5 (CommentId 6, ParentId 6)

Ve viola, dizi doğrudur, yazı altında, şimdi yorumları doğru sırayla gösterebilirsiniz. Mesajları facebook'ta olduğu gibi biçimlendirmek ve taslak oluşturmak için girin (seviye ne kadar derine giderse, soldan o kadar fazla ayrılmalıdır), ayrıca Indent adlı bir sütuna sahibim. Kökler 0'dır ve sonra sendikada c.Indent + 1 AS Girinti Kodunda, şimdi girintiyi 32px varsayalım ile çarpabilir ve yorumları güzel bir hiyerarşi ve taslakta gösterebilirsiniz.

Otomatik artış birincil anahtarını kullanmada hiçbir sorun görmüyorum CommentId SortKey'imi oluşturmak için itici güç olarak, +1 ile tohum eklenmiş bir veritabanı yönetilen anahtarını karıştırmaktan daha iyi bir değişiklik yaptığınız için tarihleri ​​(yorumlama tarihi) karıştırıyorsunuz.


0
create table pc ( parent varchar(10), child varchar(10) )

insert into pc values('a','b');
insert into pc values('a','c');
insert into pc values('b','e');
insert into pc values('b','f');
insert into pc values('a','d');
Insert into pc values('b','g');
insert into pc values('c','h');
insert into pc values('c','i');
insert into pc values('d','j');
insert into pc values('f','k');
insert into pc values('x','y');
insert into pc values('y','z');
insert into pc values('m','n');

 DECLARE @parent varchar(10) = 'a';
 WITH cte AS
 (
  select null parent, @parent child, 0 as level
   union
  SELECT  a.parent, a.child , 1 as level
    FROM pc a
   WHERE a.parent = @parent
   UNION ALL
  SELECT a.parent, a.child , c.level +    1
  FROM pc a JOIN cte c ON a.parent = c.child
  )
  SELECT distinct parent, child , level
  FROM cte
  order by level, parent

Bu size bütün torunları ve seviyeyi verecektir.
Bu yardımcı olur umarım :)

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.