2016-03-02 6 views
5

I veSeviye j veya i gibi bir ağacı nasıl alacak bir prosedür yazabilirim?

level 1   1 
       /\ 
    level 2  2 3 
        /\ 
    level 3   4 5 

gibi bir ağaç temsil edecek

 Users 
------------------------- 
id | ancestor_id | .... 
------------------------- 
1 | NULL  | .... 
2 |  1  | .... 
3 |  1  | .... 
4 |  3  | .... 
5 |  3  | .... 

gibi bir tablo Ben belirli bir kullanıcının soyundan j inci nesil yoluyla i th döndüren bir yordamı oluşturmak istiyor vardır: @jNULL olduğunu

CREATE PROCEDURE DescendantsLevel 
    @user_id INT, 
    @i INT, 
    @j INT 
AS 
    .... 

Ancak, döndürdüğü @i'dan başlayan tüm torunlar.

Örnekler:

EXEC DescendantLevel @user_id=1,@i=2,@j=NULL 

dönmek

------------------------- 
id | ancestor_id | .... 
------------------------- 
1 | NULL  | .... 
2 |  1  | .... 
3 |  1  | .... 
4 |  3  | .... 
5 |  3  | .... 

ve

EXEC DescendantLevel @user_id=1,@i=1,@j=2 

dönmek

 Users 
------------------------- 
id | ancestor_id | .... 
------------------------- 
1 | NULL  | .... 
2 |  1  | .... 
3 |  1  | .... 

Çeşitli sorular, var:

  • SQL "sonsuz" bazı kavramı temsil etmek NULL daha iyi bir değeri var mı?
  • Açıkladığım prosedürü nasıl uygularım?
  • Prosedürü basitleştirmek için veritabanını tasarlamanın daha iyi bir yolu var mı? Bir özyinelemeli CTE Kullanarak
+2

Arama yinelenen ctes. Bu tasarımı kullanırsanız bunu çözmenin en kolay yolu olacaktır. Ayrıca iç içe geçmiş kümeler modeline bitişik listeye daha iyi bir alternatif olarak bakabilirsin. –

+0

Eğer ilk örneğinizde 'i' 2 ise, neden # 1 geri gönderiliyor? –

+0

Neden bir seviye sütunu eklemiyorsunuz? Sorguyu gerçekten basitleştirir. – maraca

cevap

2

:

Bu özyineleme fazla 9999 seviyeleri (aslında SQL Server için özyineleme varsayılan sınırı, yani 100'den fazla seviyeleri ve yeni sekme 100 güvenir
DECLARE @test TABLE (id INT NOT NULL, ancestor_id INT NULL) 

DECLARE 
    @id INT = 1, 
    @i INT = 1, 
    @j INT = 2 

INSERT INTO @test (id, ancestor_id) 
VALUES 
    (1, NULL), 
    (2, 1), 
    (3, 1), 
    (4, 3), 
    (5, 3) 

;WITH CTE_Tree AS 
(
    SELECT 
     id, 
     ancestor_id, 
     1 AS lvl, 
     id AS base 
    FROM 
     @test 
    WHERE 
     id = @id 
    UNION ALL 
    SELECT 
     C.id, 
     C.ancestor_id, 
     P.lvl + 1 AS lvl, 
     P.base AS base 
    FROM 
     CTE_Tree P 
    INNER JOIN @test C ON C.ancestor_id = P.id 
    WHERE 
     lvl <= COALESCE(@j, 9999) 
) 
SELECT 
    id, 
    ancestor_id 
FROM 
    CTE_Tree 
WHERE 
    lvl BETWEEN @i AND COALESCE(@j, 9999) 

bir hata al).