如何使用具有节点可见性条件的递归 CTE 来压缩 SQL Server 中的路径?

问题描述 投票:0回答:1

我正在使用 SQL Server 中的一个数据集,该数据集表示节点之间的路径,其中每个节点都有一个可见性标志 (IsVisible)。 我的目标是通过跳过标记为不可见(IsVisible = 0)的节点并直接连接可见节点来压缩这些路径。例如,给定 A -> B(false) -> C(false) -> D 这样的路径,我想将其转换为 A -> D。

每条路径在我的表中表示为一对开始和结束节点,以及开始和结束节点的可见性标志。这是我的表的结构和一些示例数据:

CREATE TABLE Paths (
    StartNode CHAR(1),
    EndNode CHAR(1),
    StartNodeIsVisible BIT,
    EndNodeIsVisible BIT
);

INSERT INTO Paths (StartNode, EndNode, StartNodeIsVisible, EndNodeIsVisible) VALUES
('A', 'B', 1, 0),
('B', 'C', 0, 0),
('C', 'D', 0, 1);

想要的结果:

| StartNode | EndNode | Depth(optional) |
|-----------|---------|-----------------|
| A         | D       |   3             |

我尝试使用递归公共表表达式(CTE)来实现此路径压缩,但在正确跳过不可见节点并直接连接可见节点时遇到了困难。这是我尝试过的:

WITH RecursivePaths AS (
    SELECT StartNode, EndNode, StartNodeIsVisible, EndNodeIsVisible, 1 AS Depth
    FROM Paths
    WHERE StartNodeIsVisible = 1

    UNION ALL

    SELECT rp.StartNode, p.EndNode, rp.StartNodeIsVisible, p.EndNodeIsVisible, Depth + 1
    FROM RecursivePaths rp
    JOIN Paths p ON rp.EndNode = p.StartNode
    WHERE p.EndNodeIsVisible = 1 OR (p.EndNodeIsVisible = 0 AND Depth < 50)
)
SELECT *
FROM RecursivePaths
WHERE EndNodeIsVisible = 1
OPTION (MAXRECURSION 200);

我添加了选项

(MAXRECURSION 200)
,因为我得到:

声明终止。最大递归100已经用完 在语句完成之前。

虽然此代码适用于小型数据集,但路径表中的规模约为 15,000,000 行,但它会进行大量读取:约 600,000,000(我需要在中间停止它)。

问题:

  1. 如何调整递归 CTE 以通过仅包含可见节点之间的路径来正确压缩路径,从而有效地跳过任何中间不可见节点?
  2. 是否有更有效的方法来编写此查询来处理具有许多路径的大型数据集? (我对所有可能的解决方案持开放态度)
sql sql-server recursion common-table-expression
1个回答
0
投票

您可以合并立即可用的路径和深度 >=1 的闭包

WITH RecursivePaths AS (
    SELECT StartNode, EndNode, StartNodeIsVisible, EndNodeIsVisible, 1 AS Depth
    FROM Paths
    WHERE StartNodeIsVisible = 1 and EndNodeIsVisible = 0

    UNION ALL

    SELECT rp.StartNode, p.EndNode, rp.StartNodeIsVisible, p.EndNodeIsVisible, Depth + 1
    FROM RecursivePaths rp
    JOIN Paths p ON rp.EndNode = p.StartNode AND rp.EndNodeIsVisible = 0
    WHERE p.EndNodeIsVisible = 1 OR (p.EndNodeIsVisible = 0 AND Depth < 50)
)
SELECT *
FROM RecursivePaths
WHERE EndNodeIsVisible = 1
union 
SELECT *, 0
FROM Paths
WHERE StartNodeIsVisible = 1 and EndNodeIsVisible = 1
© www.soinside.com 2019 - 2024. All rights reserved.