T-SQL层次结构查询

Ing*_*var 5 t-sql sql-server loops hierarchy common-table-expression

我有一个包含分层数据的表: 在此输入图像描述

这是包含 id、父 id、名称、代码(有时未填充)、级别和 isroot 列的数据示例。在实际场景中,级别会多于 2 个,但现在让我们看一下简化的示例。

我需要做的是循环遍历所有记录并查找在层次结构的任何级别上未填充 id 的行:

  • id 范围应从 6 到 10 返回,因为它们在层次结构的任何点都没有填充代码
  • 不应返回从 1 到 5 的行,因为在层次结构中的某处提到了代码。

如何使用 T-SQL 解决这个问题?

我想到的唯一解决方案是递归(cte 或 WHILE),但我试图实现的解决方案太复杂并且没有解决问题。

JNe*_*ill 5

与 @DhruvJoshi 的答案略有不同,因为它可能有用:

WITH recCTE AS
(
    SELECT 
        id, 
        parent_id, 
        CASE WHEN CODE IS NOT NULL THEN 1 ELSE 0 END as code_check,
        1 as depth,
        CAST(id as VARCHAR(50)) as path
    FROM table
    WHERE isRootLevel = 1
    UNION ALL
    SELECT
        table.id,
        table.parent_id,
        CASE WHEN CODE IS NOT NULL OR reccte.code_check = 1 THEN 1 ELSE 0 END,
        depth + 1 as depth,
        reccte.path + CAST(table.id AS varchar(10)) as path
    FROM
        recCTE 
        INNER JOIN table ON
            recCTE.ID = table.parent_id
    WHERE depth < 20 /*just in case you start cycling/endless looping*/
)
SELECT * FROM recCTE where code_check = 0 ORDER BY path, depth;
Run Code Online (Sandbox Code Playgroud)


Roh*_*hou 5

这是另一个例子,适用于那些可能仍在与分层数据作斗争的人(像我一样)。\n假设我们有以下分层结构:

\n
CEO\n|-- Sales Director  \n\xe2\x94\x82   |-- Sales Manager 1\n\xe2\x94\x82   `-- Sales Manager 2 \n`-- Technical Director\n    |-- Product Manager\n    |-- R&D Team Lead\n    `-- QA Team Lead\n
Run Code Online (Sandbox Code Playgroud)\n

使用递归 cte获取每个节点的级别

\n

图片1

\n
CEO\n|-- Sales Director  \n\xe2\x94\x82   |-- Sales Manager 1\n\xe2\x94\x82   `-- Sales Manager 2 \n`-- Technical Director\n    |-- Product Manager\n    |-- R&D Team Lead\n    `-- QA Team Lead\n
Run Code Online (Sandbox Code Playgroud)\n

获取每个节点的路径

\n

图片2

\n
with cte as (\n    select id, parentId, roleName, 1 as lvl from roles where id = 1 -- root node\n    union all\n    select r.id, r.parentId, r.roleName, cte.lvl+1 as lvl from roles r -- child nodes\n    inner join cte on cte.id = r.parentid\n)\nselect * from cte;\n
Run Code Online (Sandbox Code Playgroud)\n

使用row_number()power()获取排序的层次树结果(父级后面跟着其所有子级,然后是每个子级的所有子级,依此类推):

\n

在此输入图像描述

\n
with cte as (\n    select id, roleName,     cast(roleName as varchar(200)) as hierPath \n    from roles where id = 1 \n    union all\n    select r.id, r.rolename, cast(cte.hierPath + \' / \' + r.rolename as varchar(200)) as hierPath\n    from roles r \n    inner join cte on cte.id = r.parentid\n)\nselect * from cte;\n
Run Code Online (Sandbox Code Playgroud)\n
\n

设置测试数据:

\n
with cte as (\n    select id, roleName, cast(roleName as varchar(200)) as hierPath, 1 as lvl, \n    row_number()over(partition by parentid order by roleName) / power(10.0,1) as sortNo\n    from roles where id = 1 \n    union all\n    select r.id, r.rolename, cast(cte.hierPath + \' / \' + r.rolename as varchar(200)) as hierPath, cte.lvl+1 as lvl,\n    cte.sortNo + row_number()over(partition by r.parentid order by r.roleName) / power(10.0,cte.lvl+1) as sortNo\n    from roles r \n    inner join cte on cte.id = r.parentid\n)\nselect * from cte \norder by sortNo;\n
Run Code Online (Sandbox Code Playgroud)\n


Dhr*_*shi 0

像这样的查询应该有效:

; with cte as 
(
select id, parent_id,code,parent_id as RootId from tableT where IsRootLevel=1
UNION ALL
select T2.id,T2.parent_id,T2.code,T1.RootId as RootId from tableT T2 join
cte T1 on T1.id=T2.parent_id and IsRootLevel=0
)   
,
cte2 as
(select id,MAX(case when code ='' then NULL else code end) over( partition by RootId) as code from cte)

select T1.* from tableT T1 left join cte2 T2 
on T1.id=T2.id
where T2.code is NULL
Run Code Online (Sandbox Code Playgroud)

See working demo