CTE 对循环数据的意外结果
Unexpected result from CTE on cyclic data
我有这个table:
CREATE TABLE [dbo].[hierarchical] (
[id] INT NOT NULL,
[parent_id] INT NULL,
[name] NVARCHAR (40) NULL
);
包含一些数据:
INSERT INTO [dbo].[hierarchical] ([id], [parent_id], [name]) VALUES (9, 11, N'43EB7203-3A7F-49A9-8C58-F18738D2BBC4')
INSERT INTO [dbo].[hierarchical] ([id], [parent_id], [name]) VALUES (10, 9, N'E202CAFA-4C0D-4A84-B02A-BF53AC3AFAB1')
INSERT INTO [dbo].[hierarchical] ([id], [parent_id], [name]) VALUES (11, 10, N'371C28E0-8C54-4A23-B28A-273979810E54')
如您所见,层次结构是循环的 9 => 11 => 10 => 9。
我正在尝试创建一个可以像这样处理这种循环数据的 CTE:
alter procedure GetHierarchicalTree
@rootid int
as begin
;with computed as (
select H.id, H.parent_id, 1 lvl, '[' + cast(H.id as nvarchar(max)) + ']' pat
from hierarchical H
where id = @rootid
union all
select H.id, H.parent_id, C.lvl + 1, C.pat + '[' + CAST(H.id as nvarchar(max)) + ']'
from computed C
inner join hierarchical H on C.id = H.parent_id
where C.pat not like '%[' + cast(H.id as nvarchar(max)) + ']%'
)
select * from computed
option (maxrecursion 0)
end
保护子句是 where C.pat not like '%[' + cast(H.id as nvarchar(max)) + ']%'
,因此如果 ID 已经包含,则停止。
但是当运行ID号为9的存储过程时:
exec gethierarchicaltree 9
sp return是 9 和 10,但不是 11,这很奇怪,因为 11 不应该在 computed.pat
中。
运行 11 returns 9 和 11,但不是 10。
更令人费解的是运行 on 10,因为sp只有returns 10.
为什么 sp 没有 return 9 和 11?
您的数据存在循环引用; 11 是 9 的父级,10 是 10 的父级,11 是 11 的父级,11 是 9 的父级,这...这不是层次结构,实际上推断某处存在设计缺陷。
我怀疑你要的是:
CREATE PROCEDURE dbo.GetHierarchicalTree @rootid int
AS BEGIN
WITH rCTE AS
(SELECT H.id,
H.parent_id,
CONVERT(varchar(MAX), QUOTENAME(H.id)) AS [name]
FROM dbo.hierarchical H
WHERE H.id = @rootid
UNION ALL
SELECT H.id,
H.parent_id,
r.[name] + CONVERT(varchar(MAX), QUOTENAME(H.id))
FROM rCTE r
JOIN dbo.hierarchical H ON r.parent_id = H.id
AND h.ID != @rootid)
SELECT *
FROM rCTE
--OPTION (MAXRECURSION 0); --As you have a circular reference I strongly recommend this OPTION. You could very overwhelm your server.
END;
GO
EXEC dbo.GetHierarchicalTree 9;
我觉得你的问题出在LIKE
,方括号[]
不应该有:
where C.pat not like '%' + cast(H.id as nvarchar(max)) + '%'
更新:
我了解到您使用方括号来分隔您的路径。在那种情况下,您必须像这样转义左括号:
where C.pat not like '%[[]' + cast(H.id as nvarchar(max)) + ']%'
您还可以更改 where 条件以使用 charindex:
CHARINDEX('[' + cast(H.id as nvarchar(max)) + ']',C.pat)=0
我有这个table:
CREATE TABLE [dbo].[hierarchical] (
[id] INT NOT NULL,
[parent_id] INT NULL,
[name] NVARCHAR (40) NULL
);
包含一些数据:
INSERT INTO [dbo].[hierarchical] ([id], [parent_id], [name]) VALUES (9, 11, N'43EB7203-3A7F-49A9-8C58-F18738D2BBC4')
INSERT INTO [dbo].[hierarchical] ([id], [parent_id], [name]) VALUES (10, 9, N'E202CAFA-4C0D-4A84-B02A-BF53AC3AFAB1')
INSERT INTO [dbo].[hierarchical] ([id], [parent_id], [name]) VALUES (11, 10, N'371C28E0-8C54-4A23-B28A-273979810E54')
如您所见,层次结构是循环的 9 => 11 => 10 => 9。
我正在尝试创建一个可以像这样处理这种循环数据的 CTE:
alter procedure GetHierarchicalTree
@rootid int
as begin
;with computed as (
select H.id, H.parent_id, 1 lvl, '[' + cast(H.id as nvarchar(max)) + ']' pat
from hierarchical H
where id = @rootid
union all
select H.id, H.parent_id, C.lvl + 1, C.pat + '[' + CAST(H.id as nvarchar(max)) + ']'
from computed C
inner join hierarchical H on C.id = H.parent_id
where C.pat not like '%[' + cast(H.id as nvarchar(max)) + ']%'
)
select * from computed
option (maxrecursion 0)
end
保护子句是 where C.pat not like '%[' + cast(H.id as nvarchar(max)) + ']%'
,因此如果 ID 已经包含,则停止。
但是当运行ID号为9的存储过程时:
exec gethierarchicaltree 9
sp return是 9 和 10,但不是 11,这很奇怪,因为 11 不应该在 computed.pat
中。
运行 11 returns 9 和 11,但不是 10。
更令人费解的是运行 on 10,因为sp只有returns 10.
为什么 sp 没有 return 9 和 11?
您的数据存在循环引用; 11 是 9 的父级,10 是 10 的父级,11 是 11 的父级,11 是 9 的父级,这...这不是层次结构,实际上推断某处存在设计缺陷。
我怀疑你要的是:
CREATE PROCEDURE dbo.GetHierarchicalTree @rootid int
AS BEGIN
WITH rCTE AS
(SELECT H.id,
H.parent_id,
CONVERT(varchar(MAX), QUOTENAME(H.id)) AS [name]
FROM dbo.hierarchical H
WHERE H.id = @rootid
UNION ALL
SELECT H.id,
H.parent_id,
r.[name] + CONVERT(varchar(MAX), QUOTENAME(H.id))
FROM rCTE r
JOIN dbo.hierarchical H ON r.parent_id = H.id
AND h.ID != @rootid)
SELECT *
FROM rCTE
--OPTION (MAXRECURSION 0); --As you have a circular reference I strongly recommend this OPTION. You could very overwhelm your server.
END;
GO
EXEC dbo.GetHierarchicalTree 9;
我觉得你的问题出在LIKE
,方括号[]
不应该有:
where C.pat not like '%' + cast(H.id as nvarchar(max)) + '%'
更新:
我了解到您使用方括号来分隔您的路径。在那种情况下,您必须像这样转义左括号:
where C.pat not like '%[[]' + cast(H.id as nvarchar(max)) + ']%'
您还可以更改 where 条件以使用 charindex: CHARINDEX('[' + cast(H.id as nvarchar(max)) + ']',C.pat)=0