Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 递归CTE返回路径中所有连接的节点_Sql Server_Recursion_Common Table Expression - Fatal编程技术网

Sql server 递归CTE返回路径中所有连接的节点

Sql server 递归CTE返回路径中所有连接的节点,sql-server,recursion,common-table-expression,Sql Server,Recursion,Common Table Expression,我有一个表,它通过将两个“节点”链接在一起来创建路径 Node ----------- Id - Primary Key Name etc... Path ------ Id - Primary Key From - FK to Node To - FK to Node 因此,这条路径: W --- X --- Y --- Z 可以这样建造: Node Id Name --- ----- 1 W 2 X 3 Y 4 Z 5 A 6 B 7

我有一个表,它通过将两个“节点”链接在一起来创建路径

Node
-----------
Id - Primary Key
Name 
etc...


Path
------
Id - Primary Key
From - FK to Node
To - FK to Node
因此,这条路径:

W --- X --- Y --- Z 
可以这样建造:

Node
Id   Name
---  -----
1    W
2    X
3    Y
4    Z
5    A
6    B
7    C


Path
Id  From     To
--- -------  -------
1   1        2
2   2        3
3   3        4
4   6        7
SELECT ROW_NUMBER() OVER (ORDER BY [Source], [Seq]) as [Id],
       Name
FROM step2
我提出了一个递归CTE查询,它给定任何节点Id,遍历路径并返回所有涉及的“路径”

declare @nodeId = 2
;WITH cte AS (

    -- ANCHOR
    -- Find one path involving Node
    SELECT top 1 p.*, 0 as [Seq] FROM dbo.Path p WHERE [From] = @nodeId or [To] = @nodeId 

    union all

    -- go left
    select leftPath.*, cte.[Seq] - 1 as [Seq]
    from [Path] leftPath
    join cte on cte.[From] = leftPath.[To] and cte.[Seq] <= 0

    union all

    -- go right
    select rightPath.*, cte.[Seq] + 1 as [Seq]
    from [Path] rightPath
    join cte on cte.[To] = rightPath.[From] and cte.[Seq] >= 0
)

SELECT cte.Id, cte.Seq, cte.From, cte.To
FROM cte 
order by [Seq]
但是,如何编写一个查询,在给定一个节点ID的情况下,遍历向左和向右的路径,并返回所有相关的不同(有序)节点

    Id   Name
    ---  -----
    1    W
    2    X
    3    Y
    4    Z

我想说的是:

DECLARE @nodeId int = 2;   

select 
*
from Node t1
inner join Path t2
on t1.Id = t2.[From] or t1.Id = t2.[To]
where t1.Id = @nodeId
order by t1.Id
我知道,上面的查询无法解决您的问题,但是,通过此查询,您得到的结果与cte相同,并且更简单。从这个查询中,如果查询还没有完成,您希望得到什么结果


但我知道这不是你想要的。为此,我需要一个完整的示例来说明您想要的结果,我读的最后一段是table节点。是吗?

我想说的是:

DECLARE @nodeId int = 2;   

select 
*
from Node t1
inner join Path t2
on t1.Id = t2.[From] or t1.Id = t2.[To]
where t1.Id = @nodeId
order by t1.Id
我知道,上面的查询无法解决您的问题,但是,通过此查询,您得到的结果与cte相同,并且更简单。从这个查询中,如果查询还没有完成,您希望得到什么结果


但我知道这不是你想要的。为此,我需要一个完整的示例来说明您想要的结果,我读的最后一段是table节点。?

这将返回您想要的结果,但对于
@nodeId int=5的情况它不返回任何内容,因为没有与该节点关联的路径

请参见我从
cte.[from]
获取
名称
,然后从最后一个id
cte.[To]
添加另一个
名称

我添加了一个源,以确保顺序与输出中显示的顺序一致。否则,因为最后两个
名称的
属于同一行,所以可能具有相反的顺序

;WITH cte AS (

    -- ANCHOR
    -- Find one path involving Node
    SELECT top 1 p.*, 0 as [Seq] FROM dbo.Path p WHERE [From] = @nodeId or [To] = @nodeId order by [From] desc

    union all

    -- go left
    select leftPath.*, cte.[Seq] - 1 as [Seq]
    from [Path] leftPath
    join cte on cte.[From] = leftPath.[To] and cte.[Seq] <= 0

    union all

    -- go right
    select rightPath.*, cte.[Seq] + 1 as [Seq]
    from [Path] rightPath
    join cte on cte.[To] = rightPath.[From] and cte.[Seq] >= 0
)

SELECT 'A' as [Source], cte.Id, cte.Seq, cte.[From], cte.[To], Node.[Name]
FROM cte 
JOIN Node
  ON cte.[From] = Node.[Id]
UNION  
SELECT 'B' as [Source], cte.Id, cte.Seq, cte.[From], cte.[To], Node.[Name]
FROM cte 
JOIN Node
  ON cte.[To] = Node.[Id]  
WHERE cte.id = (SELECT Max(Id) FROM cte)  

order by [Source], [Seq]

如果将上一个查询也放在CTE中,并调用
step2
,则可以使用如下格式:

Node
Id   Name
---  -----
1    W
2    X
3    Y
4    Z
5    A
6    B
7    C


Path
Id  From     To
--- -------  -------
1   1        2
2   2        3
3   3        4
4   6        7
SELECT ROW_NUMBER() OVER (ORDER BY [Source], [Seq]) as [Id],
       Name
FROM step2
最终输出


这将返回您想要的结果,但对于
@nodeId int=5的情况它不返回任何内容,因为没有与该节点关联的路径

请参见我从
cte.[from]
获取
名称
,然后从最后一个id
cte.[To]
添加另一个
名称

我添加了一个源,以确保顺序与输出中显示的顺序一致。否则,因为最后两个
名称的
属于同一行,所以可能具有相反的顺序

;WITH cte AS (

    -- ANCHOR
    -- Find one path involving Node
    SELECT top 1 p.*, 0 as [Seq] FROM dbo.Path p WHERE [From] = @nodeId or [To] = @nodeId order by [From] desc

    union all

    -- go left
    select leftPath.*, cte.[Seq] - 1 as [Seq]
    from [Path] leftPath
    join cte on cte.[From] = leftPath.[To] and cte.[Seq] <= 0

    union all

    -- go right
    select rightPath.*, cte.[Seq] + 1 as [Seq]
    from [Path] rightPath
    join cte on cte.[To] = rightPath.[From] and cte.[Seq] >= 0
)

SELECT 'A' as [Source], cte.Id, cte.Seq, cte.[From], cte.[To], Node.[Name]
FROM cte 
JOIN Node
  ON cte.[From] = Node.[Id]
UNION  
SELECT 'B' as [Source], cte.Id, cte.Seq, cte.[From], cte.[To], Node.[Name]
FROM cte 
JOIN Node
  ON cte.[To] = Node.[Id]  
WHERE cte.id = (SELECT Max(Id) FROM cte)  

order by [Source], [Seq]

如果将上一个查询也放在CTE中,并调用
step2
,则可以使用如下格式:

Node
Id   Name
---  -----
1    W
2    X
3    Y
4    Z
5    A
6    B
7    C


Path
Id  From     To
--- -------  -------
1   1        2
2   2        3
3   3        4
4   6        7
SELECT ROW_NUMBER() OVER (ORDER BY [Source], [Seq]) as [Id],
       Name
FROM step2
最终输出


您的查询似乎不起作用,例如
description
不存在。请把这个修好,我来看看修好了没有;请参阅:该查询与您的输出不匹配。非负
Seq
有一个问题,您共享一个
LIVE
代码,因此当我编辑时更改代码。使用底部的
FORK
创建一个单独的版本。是否尝试此操作?Seq其实并不重要,这可能与前1名获取默认订单的方式不同,我在其中添加了一个orderby子句,以便与示例相匹配。它所做的只是对结果进行正确排序您的查询似乎不起作用,例如
description
不存在。请把这个修好,我来看看修好了没有;请参阅:该查询与您的输出不匹配。非负
Seq
有一个问题,您共享一个
LIVE
代码,因此当我编辑时更改代码。使用底部的
FORK
创建一个单独的版本。是否尝试此操作?Seq其实并不重要,这可能与前1名获取默认订单的方式不同,我在其中添加了一个orderby子句,以便与示例相匹配。它所做的只是对结果进行正确排序。您是对的,一个更复杂的样本应该
select*From Node order by id
也返回所需的输出。更新的问题。添加了3个新节点和一个新路径。现在有两条路径——W-X-Y-Z和B-C。运行我原来的查询宽度nodeid 2会产生与以前相同的结果——整个路径nodeid 2(名为X)都涉及其中。我的查询返回图形的边,我希望它返回顶点。你是对的,一个更复杂的示例应该
select*From Node order by id
也返回所需的输出。更新的问题。添加了3个新节点和一个新路径。现在有两条路径——W-X-Y-Z和B-C。运行我原来的查询宽度nodeid 2会产生与以前相同的结果——整个路径nodeid 2(名为X)都涉及其中。我的查询返回图形的边,我希望它返回顶点。