查找分层数据的所有祖先

问题描述

我下面的表格帽子包含具有层次结构的数据结构

+----+----------+-------------+
| ID | ParentID |  FullPath   |
+----+----------+-------------+
|  1 | NULL     | (1)         |
|  2 | 1        | (1)/(2)     |
|  3 | 2        | (1)/(2)/(3) |
|  4 | NULL     | (4)         |
|  5 | 4        | (4)/(5)     |
|  6 | 4        | (4)/(6)     |
|  7 | 6        | (4)/(6)/(7) |
+----+----------+-------------+

如何检索某项的祖先? 例如,如果我寻找ID 3的祖先,我将得到1和2。 同样,如果我要查找7,我将得到4和6(注意5不在)。

我知道我可以通过解析列和使用动态SQL来避免在FullPath中使用CTE,但是我在创建查询时遇到了困难。

编辑: 我想要一个查询,使我能够获得项目的每个祖先行。例如,如果我希望祖先为7,则查询将返回下表:

+----+----------+-------------+
| ID | ParentID |  FullPath   |
+----+----------+-------------+
|  4 | NULL     | (4)         |
|  6 | 4        | (4)/(6)     |
+----+----------+-------------+

原因是因为我有更多描述项目的列,所以我需要获取它们并进行比较。

解决方法

如果您已经拥有完整路径作为数据的一部分,为什么不从中解析出祖先呢? var whereObj = {EMPRESA: "EMPRESA='DEMO'",QTD: "QTD IS NOT NULL "," ": "OR MONTANTE IS NOT NULL"}; var where = ""; var first_loop = true; for (const [key,value] of Object.entries(whereObj)) { if(key.trim()){ if(!first_loop) where += " AND"; where += " " + value; }else{ where += " " + value; } first_loop = false; } console.log(where);不需要动态SQL或CTE。

样本数据

string_split()

解决方案

declare @Data table
(
    ID int,ParentID int,FullPath nvarchar(50)
);

insert into @Data (ID,ParentID,FullPath) values
(1,NULL,'(1)'         ),(2,1,'(1)/(2)'     ),(3,2,'(1)/(2)/(3)' ),(4,'(4)'         ),(5,4,'(4)/(5)'     ),(6,'(4)/(6)'     ),(7,6,'(4)/(6)/(7)' );

结果

select  d.ID as SelectedID,da.*
from @Data d
cross apply string_split(d.FullPath,'/') s
join @Data da -- data ancestor
    on da.ID = convert(int,replace(replace(s.value,'(',''),')',''))
where d.ID = 7
  and d.ID <> da.ID -- filter out ID itself
order by d.ID,da.ID;
,

这可以使用自联接来完成:-

DECLARE   @Hierarchy TABLE
        (
          ID        int PRIMARY KEY,ParentID  int
          -- Non-clustered index key can be up to 1600 bytes on SQL 2016+,FullPath  varchar(1028) UNIQUE
        )
;
INSERT    @Hierarchy
        ( ID,FullPath )
VALUES
        ( 1,'(1)' ),( 2,'(1)/(2)' ),( 3,( 4,'(4)' ),( 5,'(4)/(5)' ),( 6,'(4)/(6)' ),( 7,'(4)/(6)/(7)' )
;
SELECT    N.ID,A.ID,A.ParentID,A.FullPath
FROM      @Hierarchy AS N
          INNER JOIN @Hierarchy AS A ON N.FullPath LIKE A.FullPath + '%'
WHERE     N.ID <> A.ID
ORDER BY  N.ID ASC,A.ID ASC
;

在我的测试中,上面的查询确实在FullPath上使用了唯一索引。这是一种替代方法,但它执行完整扫描而不是使用索引:-

SELECT    N.ID,A.FullPath
FROM      @Hierarchy AS N
          INNER JOIN @Hierarchy AS A ON SUBSTRING(N.FullPath,LEN(A.FullPath)) = A.FullPath 
WHERE     N.ID <> A.ID
ORDER BY  N.ID ASC,A.ID ASC
;

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...