检索路径的常用 Table 表达式
Common Table Expressions to retrieve path
我正在尝试使用递归查询来查找通过 table 结构如下的路径:
相关实体
FromKey TINYINT
ToKey TINYINT
...more....
我以为我可以做这样的事情:
DECLARE @startKey UNIQUEIDENTIFIER, @endKey UNIQUEIDENTIFIER;
SET @startKey = 0;
SET @endKey = 3;
;With findPath
AS
(
SELECT FromKey, ToKey
FROM RelatedEntities
WHERE FromKey = @startKey
UNION ALL
SELECT FromKey, ToKey
FROM RelatedEntities r
JOIN findPath b
ON r.FromKey = b.ToKey
AND r.FromKey NOT IN (SELECT FromKey FROM b)
)
SELECT * FROM findPath;
此代码失败,因为我无法在 CTE 中使用子查询。递归查询只能包含一个对 CTE 的引用,这似乎也是一条规则。 (真的吗?)也许这是一个游标或程序代码的工作,但我想我会把它放在这里,以防我错过了一种通过 CTE 找到通过 table 的路径的方法?
参数为:
- 以开始和结束键开始
- 基本查询使用开始键
- 递归查询在包含结束键时应该停止(一直无法弄清楚)并且不应重复开始键。
- 可以使用 MAXRECURSION 选项在一定次数的迭代后停止。
感谢所有 CTE 专家。直说吧。
为了便于阅读,将其从 UNIQUEIDENTIFIERS 更改为 TINYINT。 SQL 结构相同。这里有一些代码来测试它。
CREATE TABLE RelatedEntities(FromKey TINYINT, ToKey TINYINT);
INSERT RelatedEntities(FromKey, ToKey)
VALUES
(1, 0),
(0, 1),
(1, 7),
(7, 1),
(3, 4),
(4, 3)
;With FindPath
AS
(
SELECT FromKey, ToKey, 0 AS recursionLevel
FROM RelatedEntities
WHERE FromKey = 1
UNION ALL
SELECT r.FromKey, r.ToKey, recursionLevel = recursionLevel + 1
FROM RelatedEntities r
INNER JOIN FindPath b ON r.FromKey = b.ToKey
WHERE b.ToKey <> 3 AND RecursionLevel < 10
)
SELECT * FROM FindPath
ORDER BY recursionLevel
注意这个 returns 从 1 到 0,然后从 0 到 1,并重复直到我 运行 超出递归级别。
您需要像这样修改您的查询:
DECLARE @startKey UNIQUEIDENTIFIER, @endKey UNIQUEIDENTIFIER;
DECLARE @maxRecursion INT = 100
SET @startKey = '00000000-0000-0000-0000-000000000000';
SET @endKey = 'F7801327-C037-AA93-67D1-B7892F6093A7';
;With FindPath
AS
(
SELECT FromKey, ToKey, 0 AS recursionLevel
FROM RelatedEntities
WHERE FromKey = @startKey
UNION ALL
SELECT r.FromKey, r.ToKey, recursionLevel = recursionLevel +1
FROM RelatedEntities r
INNER JOIN FindPath b ON r.FromKey = b.ToKey
WHERE b.ToKey <> @endKey AND recursionLevel < @maxRecursion
)
SELECT * FROM FindPath;
上面的主播成员CTE
:
SELECT FromKey, ToKey, 0 AS recursionLevel
FROM RelatedEntities
WHERE FromKey = @startKey
将 select(从,到)记录链的 起始记录,T0
。
CTE
的递归成员:
SELECT r.FromKey, r.ToKey, recursionLevel = recursionLevel +1
FROM RelatedEntities r
INNER JOIN FindPath b ON r.FromKey = b.ToKey
WHERE b.ToKey <> @endKey AND recursionLevel < @maxRecursion
将以 T0
、T1
、... 作为输入和 T1
、T2
、... 分别作为输出执行。
此过程将继续向最终结果集添加记录,直到从递归成员返回一个空集为止,即直到将 ToKey=@endKey
的记录添加到结果集,或 @maxRecursion
级别已达到。
编辑:
您可以使用以下查询来有效处理任何循环路径:
;With FindPath
AS
(
SELECT FromKey, ToKey,
0 AS recursionLevel,
CAST(FromKey AS VARCHAR(MAX)) AS FromKeys
FROM RelatedEntities
WHERE FromKey = 1
UNION ALL
SELECT r.FromKey, r.ToKey,
recursionLevel = recursionLevel + 1,
FromKeys = FromKeys + ',' + CAST(r.FromKey AS VARCHAR(MAX))
FROM RelatedEntities r
INNER JOIN FindPath b ON r.FromKey = b.ToKey
WHERE (b.ToKey <> 3)
AND (RecursionLevel < 10)
AND PATINDEX('%,' + CAST(r.ToKey AS VARCHAR(MAX)) + ',%', ',' + FromKeys + ',') = 0
)
SELECT * FROM FindPath
ORDER BY recursionLevel
计算字段FromKeys
用于进行FromKey
到下一个递归层次。这样,来自先前递归级别的任何键都使用 字符串连接 从一个级别累积到另一个级别。 PATINDEX
然后用于检查是否满足循环路径。
我正在尝试使用递归查询来查找通过 table 结构如下的路径:
相关实体
FromKey TINYINT
ToKey TINYINT
...more....
我以为我可以做这样的事情:
DECLARE @startKey UNIQUEIDENTIFIER, @endKey UNIQUEIDENTIFIER;
SET @startKey = 0;
SET @endKey = 3;
;With findPath
AS
(
SELECT FromKey, ToKey
FROM RelatedEntities
WHERE FromKey = @startKey
UNION ALL
SELECT FromKey, ToKey
FROM RelatedEntities r
JOIN findPath b
ON r.FromKey = b.ToKey
AND r.FromKey NOT IN (SELECT FromKey FROM b)
)
SELECT * FROM findPath;
此代码失败,因为我无法在 CTE 中使用子查询。递归查询只能包含一个对 CTE 的引用,这似乎也是一条规则。 (真的吗?)也许这是一个游标或程序代码的工作,但我想我会把它放在这里,以防我错过了一种通过 CTE 找到通过 table 的路径的方法?
参数为:
- 以开始和结束键开始
- 基本查询使用开始键
- 递归查询在包含结束键时应该停止(一直无法弄清楚)并且不应重复开始键。
- 可以使用 MAXRECURSION 选项在一定次数的迭代后停止。
感谢所有 CTE 专家。直说吧。
为了便于阅读,将其从 UNIQUEIDENTIFIERS 更改为 TINYINT。 SQL 结构相同。这里有一些代码来测试它。
CREATE TABLE RelatedEntities(FromKey TINYINT, ToKey TINYINT);
INSERT RelatedEntities(FromKey, ToKey)
VALUES
(1, 0),
(0, 1),
(1, 7),
(7, 1),
(3, 4),
(4, 3)
;With FindPath
AS
(
SELECT FromKey, ToKey, 0 AS recursionLevel
FROM RelatedEntities
WHERE FromKey = 1
UNION ALL
SELECT r.FromKey, r.ToKey, recursionLevel = recursionLevel + 1
FROM RelatedEntities r
INNER JOIN FindPath b ON r.FromKey = b.ToKey
WHERE b.ToKey <> 3 AND RecursionLevel < 10
)
SELECT * FROM FindPath
ORDER BY recursionLevel
注意这个 returns 从 1 到 0,然后从 0 到 1,并重复直到我 运行 超出递归级别。
您需要像这样修改您的查询:
DECLARE @startKey UNIQUEIDENTIFIER, @endKey UNIQUEIDENTIFIER;
DECLARE @maxRecursion INT = 100
SET @startKey = '00000000-0000-0000-0000-000000000000';
SET @endKey = 'F7801327-C037-AA93-67D1-B7892F6093A7';
;With FindPath
AS
(
SELECT FromKey, ToKey, 0 AS recursionLevel
FROM RelatedEntities
WHERE FromKey = @startKey
UNION ALL
SELECT r.FromKey, r.ToKey, recursionLevel = recursionLevel +1
FROM RelatedEntities r
INNER JOIN FindPath b ON r.FromKey = b.ToKey
WHERE b.ToKey <> @endKey AND recursionLevel < @maxRecursion
)
SELECT * FROM FindPath;
上面的主播成员CTE
:
SELECT FromKey, ToKey, 0 AS recursionLevel
FROM RelatedEntities
WHERE FromKey = @startKey
将 select(从,到)记录链的 起始记录,T0
。
CTE
的递归成员:
SELECT r.FromKey, r.ToKey, recursionLevel = recursionLevel +1
FROM RelatedEntities r
INNER JOIN FindPath b ON r.FromKey = b.ToKey
WHERE b.ToKey <> @endKey AND recursionLevel < @maxRecursion
将以 T0
、T1
、... 作为输入和 T1
、T2
、... 分别作为输出执行。
此过程将继续向最终结果集添加记录,直到从递归成员返回一个空集为止,即直到将 ToKey=@endKey
的记录添加到结果集,或 @maxRecursion
级别已达到。
编辑:
您可以使用以下查询来有效处理任何循环路径:
;With FindPath
AS
(
SELECT FromKey, ToKey,
0 AS recursionLevel,
CAST(FromKey AS VARCHAR(MAX)) AS FromKeys
FROM RelatedEntities
WHERE FromKey = 1
UNION ALL
SELECT r.FromKey, r.ToKey,
recursionLevel = recursionLevel + 1,
FromKeys = FromKeys + ',' + CAST(r.FromKey AS VARCHAR(MAX))
FROM RelatedEntities r
INNER JOIN FindPath b ON r.FromKey = b.ToKey
WHERE (b.ToKey <> 3)
AND (RecursionLevel < 10)
AND PATINDEX('%,' + CAST(r.ToKey AS VARCHAR(MAX)) + ',%', ',' + FromKeys + ',') = 0
)
SELECT * FROM FindPath
ORDER BY recursionLevel
计算字段FromKeys
用于进行FromKey
到下一个递归层次。这样,来自先前递归级别的任何键都使用 字符串连接 从一个级别累积到另一个级别。 PATINDEX
然后用于检查是否满足循环路径。