我有一个表FolderXDoc:
CREATE TABLE [dbo].[FolderXDoc](
[fldid] [int] NOT NULL,
[Xorder] [int] NOT NULL,
[docid] [int] NOT NULL,
CONSTRAINT [FolderXDoc$pk] PRIMARY KEY CLUSTERED
(
[fldid] ASC,
[Xorder] ASC,
[docid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
我的应用程序允许在此表中进行循环引用,因此允许使用以下数据:
fldid|Xorder|docid
1|1|2
2|1|3
3|1|4
4|1|2
因此文件夹1包含文件夹2,其中包含文件夹3.文件夹3包含文件夹4.文件夹4包含文件夹2,因此我们有一个周期(1/2/3/4/2/3/4/2/3 / 4 /...)
现在我想以递归方式检索文件夹中所有包含的元素。我用CTE尝试了这个,但由于数据的循环,这不起作用。我想在检测到循环时停止递归。因此,当我检索包含1的元素时,我期望结果集(2,3,4)。
我尝试使用用户定义的函数:
CREATE FUNCTION [dbo].[DocChildren](@fldid int)
RETURNS TABLE
AS
RETURN
(
WITH n AS
(SELECT f.fldid, f.docid
FROM folderxdoc f where f.fldid = @fldid
UNION ALL
SELECT n.fldid, nplus1.docid
FROM folderxdoc as nplus1, n
WHERE n.docid = nplus1.fldid and n.docid != @fldid)
SELECT docid FROM n
)
该函数处理起始id的循环循环,但不在循环发生在包含的元素中时。 我该怎么做才能解决这个问题?
感谢您的帮助!
答案 0 :(得分:1)
也许用于标记访问节点的临时表可能有所帮助。
基本上,当您访问每个节点时,将其推入临时表并针对临时表检查每个节点。找到现有节点时停止。
可能需要游标来实现这一点,尽管可能很糟糕。
答案 1 :(得分:1)
我使用@HaBo的提示解决了这个问题。
我在递归期间组装了路径并检查了重复的条目。您可以在此处找到生成的查询: http://sqlfiddle.com/#!3/cc8b3/1
WITH n AS
(SELECT f.fldid, f.docid, ',' + cast(f.fldid as varchar(max)) + ',' levels
FROM folderxdoc f where f.fldid = 1
UNION ALL
SELECT n.fldid, nplus1.docid,n.levels+ cast(n.docid as varchar(max)) + ',' levels
FROM folderxdoc as nplus1, n
WHERE n.docid = nplus1.fldid AND
n.levels not like ('%,' + cast(nplus1.docid as varchar(max)) + ',%')
)
SELECT fldid, docid, levels FROM n