我正在使用Split功能(可在social.msdn.com上找到)并在查询窗口中手动执行时
SELECT * FROM dbo.Split('/ABC/DEF/GHI/JKL', '/')
我得到以下
Id Name
-- ----
1
2 ABC
3 DEF
4 GHI
5 JKL
其中 Id 只是表示原始字符串中位置的序号,名称是该节点的名称。还没有分层信息。
现在,下一步是将其放入DB中的分层数据结构中。我试图在存储过程中执行此操作,并且我的SQL技能就是它们,我已经碰壁了。以下是我喜欢的内容:(请注意,上面的Id列与此处的Id或ParentId列无关。)
Id ParentId Name FullName
-- -------- ---- --------
1 NULL ABC /ABC
2 1 DEF /ABC/DEF
3 2 GHI /ABC/DEF/GHI
4 3 JKL /ABC/DEF/GHI/JKL
我的SP(使用param @FullName称为GetId)得到了这么多 - GetId应该返回与此节点关联的Id。如果该节点不存在,则应该创建它并且应该返回该新行的Id - 换句话说,该SP的消费者在调用它之前不应该关心或知道节点是否存在:
DECLARE @count int
-- // is there already a row for this node?
SELECT @count = COUNT(CatId)
FROM Category
WHERE FullName = @FullName
-- // if no row for this node, create the row
-- // and perhaps create multiple rows in hierarchy up to root
IF (@count = 0)
BEGIN
SELECT * FROM Split(@FullName, '/')
-- // NOW WHAT ???
-- // need to insert row (and perhaps parents up to root)
END
-- // at this point, there should be a row for this node
-- // return the Id associated with this node
SELECT Id
FROM Category
WHERE FullName = @FullName
这些项最终将通过一系列插入结束的类别表(邻接列表)具有以下结构。
CREATE TABLE Category (
Id int IDENTITY(1,1) NOT NULL PRIMARY KEY,
ParentId int NULL,
Name nvarchar(255) NOT NULL,
FullName nvarchar(255) NOT NULL)
因此,我不想为Category表中的Id列生成值,需要为每个节点获取相应的ParentId。
在路径'/ ABC / DEF / GHI / JKL'和'/ ABC / DEF / XYZ / LMN / OPQ'处理完毕后我做了一个SELECT * FROM Category,我希望看到以下内容:
Id ParentId Name FullName
-- -------- ---- --------
1 NULL ABC /ABC
2 1 DEF /ABC/DEF
3 2 GHI /ABC/DEF/GHI
4 3 JKL /ABC/DEF/GHI
5 2 XYZ /ABC/DEF/XYZ
6 5 LMN /ABC/DEF/XYZ/LMN
7 6 OPQ /ABC/DEF/XYZ/LMN/OPQ
Q :是否可以从最外层节点开始递归地回调SP,直到节点存在或我们处于最终父节点?有什么影响:
GetId(@FullName)
{
If Category exists with @FullName
return CatId
Else // row doesn't exist for this node
Split @FullName, order by Id DESC so we get the leaf node first
Create Category row
@FullName,
@Name,
@ParentId = Id of next FullName (call GetId with FullName of next row from Split)
}
答案 0 :(得分:3)
您可以使用CTE与RowNumbering结合使用
With TMP AS (
SELECT Id, Data as Name, RN=ROW_NUMBER() over (Order by Id ASC)
FROM dbo.Split('/ABC/DEF/GHI/JKL', '/')
where Data > ''
), TMP2 AS (
SELECT TOP 1 RN, CONVERT(bigint, null) ParentId, Name, convert(nvarchar(max),'/' + Name) FullName
From TMP
Order by RN
union all
SELECT n.RN, t.RN, n.Name, t.FullName + '/' + n.Name
from TMP2 t
inner join TMP n on n.RN = t.RN+1)
select *
from tmp2
order by RN
现在,对于第二部分,这将插入整个层次结构,但以ID = 1
开头IF (@count = 0)
BEGIN
With TMP AS (
SELECT Id, Data as Name, RN=ROW_NUMBER() over (Order by Id ASC)
FROM dbo.Split('/ABC/DEF/GHI/JKL', '/')
where Data > ''
), TMP2 AS (
SELECT TOP 1 RN, CONVERT(bigint, null) ParentId, Name, convert(nvarchar(max),'/' + Name) FullName
From TMP
Order by RN
union all
SELECT n.RN, t.RN, n.Name, t.FullName + '/' + n.Name
from TMP2 t
inner join TMP n on n.RN = t.RN+1)
insert Category(CatId, ParentId, Name, FullName) --<< list correct column names
select RN, ParentId, Name, FullName
from tmp2
order by RN
END