【问题标题】:How to write this recursive CTE for SQL Server?如何为 SQL Server 编写这个递归 CTE?
【发布时间】:2020-08-31 14:47:46
【问题描述】:

为简单起见,我的架构:

  1. 文件夹表(FolderId、ParentFolderId)

  2. DeviceFolderProperties 表(FolderId、LogDataRetentionDaysEvent)

并非每个文件夹都有保留日。然而,这是一个继承的值。如何在 SQL 中编写一些东西来返回每个文件夹及其保留日期,如果为 null,则返回其继承值。

继承有多个层次,因此需要遍历树。

这是我尝试过的:

;
WITH [cte]
AS 
(
    SELECT f.FolderId, f.ParentFolderId, dfp.LogDataRetentionDaysEvent
    FROM [Folders] f
    LEFT JOIN DeviceFolderProperties dfp
    ON f.FolderId = dfp.FolderId
), 
[cte_collapse] 
AS --recurse where r days is null
(

    SELECT c.FolderId, c.ParentFolderId, c.LogDataRetentionDaysEvent
    FROM [cte] c
    WHERE c.LogDataRetentionDaysEvent IS NULL

    UNION ALL

    SELECT c.FolderId, c.ParentFolderId, ISNULL(c.LogDataRetentionDaysEvent, cc.LogDataRetentionDaysEvent)
    FROM [cte] c
    JOIN [cte_collapse] cc ON cc.FolderId = c.ParentFolderId

)
SELECT
    *
FROM 
    [cte_collapse]

【问题讨论】:

  • SQL 中没有继承。您正在使用递归 CTE 执行分层查询。一个更简单且绝对快很多倍的方法是使用hierarchyid type 而不是父/子连接。 hierarchyid 存储层次结构的“路径”,这使得查找子级就像查找 path 以根路径开头的行一样容易。这种搜索可以利用索引来加速查询

标签: sql sql-server left-join recursive-query hierarchical-query


【解决方案1】:

你可以这样写:

with 
    data as (
        select f.FolderID, f.ParentFolderId, dfp.LogDataRetentionDaysEvent
        from Folders f
        left join DeviceFolderProperties dfp on dfp.FolderID = f.FolderID
    ),
    cte as (
        select d.*, FolderID OriginalFolderId
        from data d
        union all
        select d.*, c.OriginalFolderId
        from cte c
        inner join data d on d.FolderID = c.ParentFolderId
        where c.LogDataRetentionDaysEvent is null
    )
select OriginalFolderId, max(LogDataRetentionDaysEvent) LogDataRetentionDaysEvent
from cte 
group by OriginalFolderId

我们首先生成一个包含来自两个表的信息的派生表。然后,对于每条记录,递归查询爬上层次结构,在每个级别搜索非空保留。诀窍是在遇到匹配时立即停止。

【讨论】:

    猜你喜欢
    • 2012-04-23
    • 2014-05-19
    • 1970-01-01
    • 1970-01-01
    • 2018-12-13
    • 2012-12-25
    • 1970-01-01
    • 1970-01-01
    • 2020-06-08
    相关资源
    最近更新 更多