2010-02-26 26 views
18

cho một cấu trúc dữ liệu đơn giản như vậy:số đếm của trẻ em trong dữ liệu SQL thứ bậc

ID parentID Text  Price 
1     Root 
2  1   Flowers 
3  1   Electro 
4  2   Rose  10 
5  2   Violet  5 
6  4   Red Rose 12 
7  3   Television 100 
8  3   Radio  70 
9  8   Webradio 90 

Để tham khảo, cây thứ bậc như sau:

ID Text  Price 
1  Root 
|2 Flowers 
|-4 Rose  10 
| |-6 Red Rose 12 
|-5 Violet  5 
|3 Electro 
|-7 Television 100 
|-8 Radio  70 
    |-9 Webradio 90 

Tôi muốn tính số lượng trẻ em trên mỗi cấp độ. Vì vậy, tôi sẽ nhận được một cột mới "NoOfChildren" như vậy:

ID parentID Text  Price NoOfChildren 
1     Root    8 
2  1   Flowers   3 
3  1   Electro   3 
4  2   Rose  10  1 
5  2   Violet  5  0 
6  4   Red Rose 12  0 
7  3   Television 100 0 
8  3   Radio  70  1 
9  8   Webradio 90  0 

tôi đọc một vài điều về dữ liệu phân cấp, nhưng tôi bằng cách nào đó gặp khó khăn trên nhiều bên tham gia trên parentIDs. Có lẽ ai đó có thể giúp tôi ở đây.

+0

Bạn hệ thống quyền cây không phù hợp với đầu vào của bạn. –

+0

Và đầu ra của bạn dường như không khớp với hệ thống phân cấp của bạn . Từ việc nhìn vào hệ thống phân cấp của bạn, tôi sẽ giả định ID & 4 của ID có 0 con. –

+0

bạn hoàn toàn chính xác, sai lầm với cây phân cấp + đầu ra, sẽ sửa chữa –

Trả lời

21

Sử dụng CTE sẽ giúp bạn có được những gì bạn muốn.

  • Theo dõi đệ quy tất cả trẻ em, ghi nhớ thư mục gốc.
  • COUNT các mục cho mỗi gốc.
  • JOIN lại một lần nữa với bảng gốc để tạo kết quả.

dữ liệu thử nghiệm

DECLARE @Data TABLE (
    ID INTEGER PRIMARY KEY 
    , ParentID INTEGER 
    , Text VARCHAR(32) 
    , Price INTEGER 
) 

INSERT INTO @Data 
    SELECT 1, Null, 'Root', NULL 
    UNION ALL SELECT 2, 1, 'Flowers', NULL 
    UNION ALL SELECT 3, 1, 'Electro', NULL 
    UNION ALL SELECT 4, 2, 'Rose', 10 
    UNION ALL SELECT 5, 2, 'Violet', 5 
    UNION ALL SELECT 6, 4, 'Red Rose', 12 
    UNION ALL SELECT 7, 3, 'Television', 100 
    UNION ALL SELECT 8, 3, 'Radio', 70 
    UNION ALL SELECT 9, 8, 'Webradio', 90 

SQL Statement

;WITH ChildrenCTE AS (
    SELECT RootID = ID, ID 
    FROM @Data 
    UNION ALL 
    SELECT cte.RootID, d.ID 
    FROM ChildrenCTE cte 
      INNER JOIN @Data d ON d.ParentID = cte.ID 
) 
SELECT d.ID, d.ParentID, d.Text, d.Price, cnt.Children 
FROM @Data d 
     INNER JOIN (
      SELECT ID = RootID, Children = COUNT(*) - 1 
      FROM ChildrenCTE 
      GROUP BY RootID 
     ) cnt ON cnt.ID = d.ID 
+0

Cảm ơn câu trả lời rõ ràng của bạn, giải pháp hoàn hảo. Bạn muốn khai sáng cho tôi về cách sử dụng ";"? Đôi khi tôi nhận được một lỗi cú pháp khi sử dụng WITH statements, rằng tôi không có khó chịu ";". Tôi có phải luôn luôn "thoát" với các câu lệnh kèm theo không? –

+3

@moontear: mệnh đề 'WITH' xác định' CTE' có thể kết hợp với mệnh đề 'WITH' xác định gợi ý bảng. Trước đây phải được tách biệt rõ ràng bằng dấu chấm phẩy nếu nó không phải là câu lệnh đầu tiên trong lô. – Quassnoi

+0

+1, gần như khó khăn như một ứng dụng CROSS bằng cách sử dụng một chức năng tách, không phổ biến mặc dù ;-) –

5

Xem xét sử dụng một cây preorder traversal cách sửa đổi của lưu trữ các dữ liệu phân cấp. Xem http://www.sitepoint.com/hierarchical-data-database/

số Xác định trẻ em đối với bất kỳ nút sau đó trở thành một đơn giản:

SELECT (right-left-1)/2 AS num_children FROM ... 
+0

Bạn tiết kiệm cho tôi rất nhiều thời gian. Câu trả lời hay nhất cho tôi :) –

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