2012-04-06 39 views
5

Vì vậy, tôi có hai bảng có cấu trúc như sau:T-SQL nút get gốc trong hệ thống phân cấp

CREATE TABLE #nodes(node int NOT NULL); 
ALTER TABLE #nodes ADD CONSTRAINT PK_nodes PRIMARY KEY CLUSTERED (node); 

CREATE TABLE #arcs(child_node int NOT NULL, parent_node int NOT NULL); 
ALTER TABLE #arcs ADD CONSTRAINT PK_arcs PRIMARY KEY CLUSTERED (child_node, parent_node); 

INSERT INTO #nodes(node) 
VALUES (1), (2), (3), (4), (5), (6), (7); 

INSERT INTO #arcs(child_node, parent_node) 
VALUES (2, 3), (3, 4), (2, 6), (6, 7); 

Nếu tôi có hai nút, cho phép nói 1 và 2. Tôi muốn có một danh sách các nút gốc của họ. Trong trường hợp này, nó sẽ là 1, 4 và 7. Làm thế nào tôi có thể viết một truy vấn để đưa cho tôi thông tin đó?

Tôi đã đâm vào viết nó nhưng chạy vào vấn đề mà tôi không thể sử dụng một LEFT tham gia trong phần đệ quy của một CTE cho một số lý do không rõ. Đây là truy vấn sẽ hoạt động nếu tôi được phép thực hiện LEFT JOIN.

WITH root_nodes 
AS (
    -- Grab all the leaf nodes I care about and their parent 
    SELECT n.node as child_node, a.parent_node 
    FROM #nodes n 
    LEFT JOIN #arcs a 
     ON n.node = a.child_node 
    WHERE n.node IN (1, 2) 

    UNION ALL 

    -- Grab all the parent nodes 
    SELECT rn.parent_node as child_node, a.parent_node 
    FROM root_nodes rn 
    LEFT JOIN #arcs a -- <-- LEFT JOINS are Illegal for some reason :(
     ON rn.parent_node = a.child_node 
    WHERE rn.parent_node IS NOT NULL 
) 
SELECT DISTINCT rn.child_node as root_node 
FROM root_nodes rn 
WHERE rn.parent_node IS NULL 

Có cách nào tôi có thể cấu trúc lại truy vấn để có được những gì tôi muốn không? Tôi không thể tái cơ cấu dữ liệu và tôi thực sự thích tránh xa các bảng tạm thời hoặc phải làm bất cứ điều gì đắt tiền.

Cảm ơn, Raul

Trả lời

5

Làm thế nào về cách di chuyển LEFT JOIN ra khỏi CTE?

WITH root_nodes 
AS (
    -- Grab all the leaf nodes I care about 
    SELECT NULL as child_node, n.node as parent_node 
    FROM #nodes n 
    WHERE n.node IN (1, 2) 

    UNION ALL 

    -- Grab all the parent nodes 
    SELECT rn.parent_node as child_node, a.parent_node 
    FROM root_nodes rn 
     JOIN #arcs a 
     ON rn.parent_node = a.child_node 
) 
SELECT DISTINCT rn.parent_node AS root_node 
FROM root_nodes rn 
    LEFT JOIN #arcs a 
    ON rn.parent_node = a.child_node 
WHERE a.parent_node IS NULL 

Tập kết quả là 1, 4, 7.

+0

Đó là tuyệt vời! Không biết tại sao tôi không nghĩ về điều đó. Tôi có câu hỏi, khi tôi nhìn vào kế hoạch thực hiện nó làm cho bên trái tham gia quét chỉ mục nhóm. Tại sao nó không chọn một sự tìm kiếm như phần đệ quy đang làm? – HaxElit

+0

Tôi không biết tại sao. Tôi đã thử thêm 'WITH (INDEX (PK_arcs))', nhưng hóa ra, trên tập dữ liệu nhỏ này, tìm kiếm thực sự hơi đắt hơn một lần quét. Có thể với một tập hợp dữ liệu lớn, trình tối ưu hóa sẽ chọn tìm kiếm thay thế. –

+0

Quét không nhất thiết là một điều xấu. Với bộ dữ liệu nhỏ này, việc hút toàn bộ chỉ mục nhóm trong một lần thay vì làm theo cách hiệu quả hơn. Tôi chắc chắn rằng có một điểm tới hạn. –

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