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”部门的孩子!

谢谢你。

4

3 回答 3

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
    )

让我知道您是否想出任何它中断的情况。

于 2010-06-16T19:54:40.350 回答
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
于 2010-06-16T17:34:53.650 回答
1

问题中存在不匹配。查询返回:node.namedepthnode.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
于 2010-06-17T00:52:35.547 回答