我已经构建了一个函数/查询,它将[paths]作为邻接列表返回,如下所示,它运行良好, 但我想弄清楚如何将结果限制为仅完整路径,而不是每次深度(n)的迭代。
例如,在下面显示的以下结果中,只有这些是有效的,我想要返回或过滤的完整路径:
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Close>B-GARNER>VB1>VB1_Close
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Close>B-GARNER>VB1>VB1_Open
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Close>B-GARNER>VB1>VB2
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Open>V30A2>V30A2_Close>S2-UG
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Open>V30A2>V30A2_Open>S1-UG
TEST
通过DPath从fn_Get_SubTreePaths('S11',11)中选择*
S11>S11-LG
S11>S11-LG>V613
S11>S11-LG>V613>V613_Close
S11>S11-LG>V613>V613_Close>B31A
S11>S11-LG>V613>V613_Close>B31A>B30
S11>S11-LG>V613>V613_Close>B31A>B30>B30A
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Close
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Close>B-GARNER
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Close>B-GARNER>VB1
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Close>B-GARNER>VB1>VB1_Close
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Close>B-GARNER>VB1>VB1_Open
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Close>B-GARNER>VB1>VB2
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Open
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Open>V30A2
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Open>V30A2>V30A2_Close
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Open>V30A2>V30A2_Close>S2-UG
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Open>V30A2>V30A2_Open
S11>S11-LG>V613>V613_Close>B31A>B30>B30A>V30A1>V30A1_Open>V30A2>V30A2_Open>S1-UG
换句话说 - 我怎样才能确定那些包含遍历/深度中最底部项目的路径?
任何帮助将不胜感激!我正在阅读Joe Celko在SQL for Treesies中的树和层次结构 - 但到目前为止还没有把我的大脑包裹起来如何正确地限制结果......
这是代码;
create function [dbo].[fn_Get_SubTreePaths]( @Start varchar(20), @MaxLevels int)
returns table
as
RETURN(
WITH CTE AS (
SELECT
c.DeviceID AS Start,
CAST(d.DeviceName AS VARCHAR(2000)) AS Path,
c.ConnectedDeviceID,
1 AS Level
FROM Connections c
INNER JOIN Devices d ON d.ID=c.DeviceID
AND d.DeviceName=@Start
UNION ALL
SELECT
r.Start,
CAST(r.Path + '>'+ d.DeviceName AS VARCHAR(2000)),
--CAST(r.Path + ' -> ' + d.DeviceName + '-' + cast(r.SLevel as varchar) AS VARCHAR),
c.ConnectedDeviceID,
Level = r.Level + 1
FROM Connections c
INNER JOIN Devices d ON d.ID=c.DeviceID
and d.DeviceName<>@Start
INNER JOIN CTE r ON c.DeviceID=r.ConnectedDeviceID
AND r.Level < @MaxLevels
)
SELECT
DISTINCT a.DPath
FROM (
SELECT c.Path + '>' + ISNULL(d.DeviceName,'?') AS DPath
FROM CTE c
INNER JOIN Devices d ON d.ID=c.ConnectedDeviceID
) a
)
CREATE TABLE [dbo].[Connections](
[ID] [int] NOT NULL,
[DeviceID] [int] NULL,
[ConnectedDeviceID] [int] NULL
CONSTRAINT [PK_Connections] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[Devices](
[ID] [int] IDENTITY(1,1) NOT NULL,
[DeviceName] [varchar](50) NULL
CONSTRAINT [PK_Devices] PRIMARY KEY CLUSTERED
(
[ID] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CTE使用的观点:
ALTER view [dbo].[vw_DeviceConnections] as
select
c.ID as ID,
c.DeviceID as DeviceID,
d.DeviceName,
d.DeviceType,
c.ConnectedDeviceID as ConnDeviceID,
cd.DeviceName as ConnDeviceName,
cd.DeviceType as ConnDeviceType
from Devices d
inner join Connections c on
d.id=c.DeviceID
inner join Devices cd on
cd.id=c.ConnectedDeviceID
答案 0 :(得分:2)
查看有关SQLFiddle here的答案。
这是我的策略:让你的递归CTE返回当前节点以及它之前的节点。然后,您可以将其连接到自身并将其限制为最后一个节点未用作另一个节点的父节点的行。
以下是您的功能的外观(用参数替换'S11'和15):
WITH CTE AS (
SELECT
d.ID AS Start,
CAST(d.DeviceName AS VARCHAR(2000)) AS Path,
d.ID AS node,
NULL AS parent,
1 AS Level
FROM Devices d
WHERE d.DeviceName= 'S11'
UNION ALL
SELECT
r.Start,
CAST(r.Path + '>'+ d.DeviceName AS VARCHAR(2000)),
d.ID as node,
r.node as parent,
r.Level + 1 as Level
FROM CTE r
INNER JOIN Connections c ON c.DeviceID = r.node
INNER JOIN Devices d ON d.ID = c.ConnectedDeviceID
WHERE r.Level < 15
),
Trimmed as (
SELECT L.*
FROM CTE L
LEFT JOIN CTE R on L.node = R.parent
WHERE R.parent IS NULL
)
SELECT * FROM Trimmed
如果您想澄清它是如何运作的,请告诉我,我可以尝试更好地解释它。
答案 1 :(得分:0)
尝试下一个解决方案
select
*
from
fn_Get_SubTreePaths('S11', 11) f1
where
(
select
count(*)
from
fn_Get_SubTreePaths('S11', 11) f2
where
charindex(f1.dPath, f2.dPath) > 0
) = 1
order by DPath