2016-03-02 39 views
5

Tôi có một bảng nhưLàm thế nào tôi có thể viết một thủ tục được cấp i qua j hoặc một cây như thế này?

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

đó sẽ đại diện cho một cây như

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

và tôi muốn tạo một thủ tục mà trả về thứ i qua thế hệ thứ j của hậu duệ của một người sử dụng đưa ra:

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

Nếu @jNULL, tuy nhiên, nó trả về tất cả các con cháu bắt đầu từ thế hệ @i.

Ví dụ:

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

sẽ trở

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

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

sẽ trở

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

Một số câu hỏi, tôi có:

  • Có một giá trị tốt hơn so với NULL để đại diện cho một số khái niệm về "vô cực" trong SQL?
  • Làm cách nào để triển khai quy trình tôi đã mô tả?
  • Có cách nào tốt hơn để thiết kế cơ sở dữ liệu để đơn giản hóa quy trình không?
+2

Tra cứu các byte đệ quy. Đây sẽ là cách dễ nhất để giải quyết vấn đề này nếu bạn sử dụng thiết kế này. Bạn cũng có thể xem mô hình tập hợp lồng nhau như là một lựa chọn tốt hơn cho danh sách kề. –

+0

Nếu '@ i' là 2 trong ví dụ đầu tiên của bạn thì tại sao id # 1 được trả về? –

+0

Tại sao không thêm cột cấp? Làm cho truy vấn thực sự đơn giản. – maraca

Trả lời

2

Sử dụng một CTE đệ quy:

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) 

này dựa vào không quá 9999 mức độ đệ quy (trên thực tế giới hạn mặc định trên đệ quy cho SQL Server là 100, vì vậy hơn 100 cấp độ và bạn sẽ gặp lỗi).

Các vấn đề liên quan