2010-06-16 43 views
3

我使用的嵌套集模型稍後將用於爲我的網站構建網站地圖。這是我的表格結構。按名稱對嵌套集進行排序,同時保持深度完整

create table departments (
    id int identity(0, 1) primary key 
    , lft int 
    , rgt int 
    , name nvarchar(60) 
); 

insert into departments (lft, rgt, name) values (1, 10, 'departments'); 
insert into departments (lft, rgt, name) values (2, 3, 'd'); 
insert into departments (lft, rgt, name) values (4, 9, 'a'); 
insert into departments (lft, rgt, name) values (5, 6, 'b'); 
insert into departments (lft, rgt, name) values (7, 8, 'c'); 

如何根據深度和名稱進行排序?我能做

select 
    replicate('----', count(parent.name) - 1) + ' ' + node.name 
    , count(parent.name) - 1 as depth 
, node.lft 
from 
    departments node 
    , departments parent 
where 
    node.lft between parent.lft and parent.rgt 
group by 
    node.name, node.lft 
order by 
    depth asc, node.name asc; 

但是,由於某種原因,這與孩子的父母不符。

department  lft  rgt 
--------------------------- 
departments 0  1 
---- a  1  4 
---- d  1  2 
-------- b 2  5 
-------- c 2  7 

正如你所看到的,部門'd'有部門'a的孩子!

謝謝。

回答

2

我想我終於想出了一個ANSI SQL解決方案。其基本要點是它計算父節點的父節點的值與節點自己父節點的父節點的值相同,或者節點本身與節點在同一級別上,並且具有較低的值名稱。您需要對其進行微調,以便在需要時添加縮進。另外,我不知道在大數據集的表現如何將是由於所有的子查詢:

SELECT 
    N1.name 
FROM 
    dbo.departments N1 
ORDER BY 
    (
    SELECT 
     COUNT(DISTINCT N2.lft) 
    FROM 
     dbo.departments N2 
    INNER JOIN (
       SELECT 
        N.name, 
        N.lft, 
        N.rgt, 
        (SELECT COUNT(*) FROM dbo.departments WHERE lft < N.lft AND rgt > N.lft) AS depth 
       FROM 
        dbo.departments N) SQ1 ON 
     SQ1.lft <= N2.lft AND SQ1.rgt >= N2.lft 
    INNER JOIN (
       SELECT 
        N3.name, 
        N3.lft, 
        N3.rgt, 
        (SELECT COUNT(*) FROM dbo.departments WHERE lft < N3.lft AND rgt > N3.lft) AS depth 
       FROM 
        dbo.departments N3) SQ2 ON 
     SQ2.lft <= N1.lft AND SQ2.rgt >= N1.lft AND 
     SQ2.depth = SQ1.depth AND 
     SQ2.name > SQ1.name 
    ) 

讓我知道如果你拿出它打破任何情況。

1

以下內容將與您的示例一起使用,但如果名稱包含「 - 」字符,則可能會出現故障。但它可能是一個起點。這使用CTE,我相信這是特定於SQL Server的。如果我想到更通用的ANSI SQL方法,我也會發布它。

;WITH Tree_Path AS (
    SELECT 
     lft, 
     rgt, 
     name, 
     CAST(name + '-' AS VARCHAR(MAX)) AS tree_path, 
     1 AS depth 
    FROM 
     dbo.departments 
    WHERE 
     lft = 1 
    UNION ALL 
    SELECT 
     c.lft, 
     c.rgt, 
     c.name, 
     CAST(tp.tree_path + c.name + '-' AS VARCHAR(MAX)), 
     tp.depth + 1 
    FROM 
     Tree_Path tp 
    INNER JOIN dbo.departments AS c ON 
     c.lft > tp.lft AND 
     c.lft < tp.rgt AND 
     NOT EXISTS (SELECT * FROM dbo.departments d WHERE d.lft < c.lft AND d.rgt > c.lft AND d.lft > tp.lft AND d.lft < tp.rgt)) 
SELECT 
    REPLICATE('----', depth - 1) + name, 
    depth - 1, 
    lft 
FROM 
    Tree_Path 
ORDER BY 
    tree_path, 
    name 
+0

貌似WITH子句是SQL服務器> 2005。任何方式來複制查詢的功能可能是內聯視圖? – Mike 2010-06-16 18:29:12

+2

我不這麼認爲。不幸的是,這基本上涉及遞歸,因爲您必須從所有後代獲取名稱。具有諷刺意味的是,這是使用嵌套集模型的最大原因之一 - 擺脫遞歸。當然,鏈表模式也無助於避免遞歸。 – 2010-06-16 18:37:24

+0

順便說一句,你可能已經注意到了這一點,但一個簡單的「ORDER BY lft」幾乎讓你在那裏 - 孩子們坐在父母的下方,但在深度之內,它不是按字母順序排序。 – 2010-06-16 18:39:02

1

問題存在不匹配。該查詢返回:node.namedepth,並且node.lft - 但結果表都標有:

department  lft  rgt 

反正就是查詢返回的部門級正確的結果 - 這顯然不是你想要的深度在這種情況下意味着。 ad是最高級別的部門。

如果你想子部門的數量以及嵌套集保存保養得當,則查詢很簡單:

SELECT 
    D1.name, 
    (D1.rgt - D1.lft - 1)/2 AS SubordinateDepartments 
FROM 
    departments AS D1 
ORDER BY 
    SubordinateDepartments DESC, 
    D1.name 
+0

我不認爲他想要計數的孩子。他正在尋找所有節點的列表,但是以樹狀結構,以便孩子在父母之後列出,但是在任何給定級別中,節點都按名稱排序。 – 2010-06-17 13:50:15

+0

該問題需要由OP進行澄清。理想情況下,他的理想結果表。 – 2010-06-18 01:28:28

相關問題