我想在SQL Server 2008中使用新的HierarchyID类型来处理小型wiki应用程序中的页面关系。但是,它需要有多个根节点,因为每个帐户的每个主要文章/页面都是根节点。
从我读过的HierarchyID类型中,每列只允许1个根节点是否正确?有没有办法启用多个根节点?
答案 0 :(得分:29)
我一直在做一些测试,看来你不需要带有根hierarchyid的记录。
例如,通常你会有一个根节点(级别1)和多个孩子,但是你可以跳过根节点,没有根记录,只记录从级别2开始的记录:
//table schema
CREATE TABLE [Entity](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL
[Hierarchy] [hierarchyid] NOT NULL,
CONSTRAINT [PK_Entity] PRIMARY KEY CLUSTERED
(
[ID] ASC
)
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
//Insert first 'root', which is technicall a child without a parent
INSERT INTO [Entity]
([Name]
,[Description]
,[Hierarchy])
VALUES
('Root A'
,hierarchyid::GetRoot().GetDescendant(NULL,NULL))
//Create the second 'root'
INSERT INTO [Entity]
([Name]
,[Hierarchy])
VALUES
('Root B'
,hierarchyid::GetRoot().GetDescendant((select MAX(hierarchy) from entity where hierarchy.GetAncestor(1) = hierarchyid::GetRoot()),NULL))
现在,如果您从表格中选择所有行,您会看到:
SELECT [ID]
,[Name]
,[Hierarchy],
[Hierarchy].ToString()
FROM [Entity]
ID名称层次结构(无列名称)
1根A 0x58 / 1 /
2根B 0x68 / 2 /
我不确定这是否是推荐的练习,但从概念上讲它允许你有多个根,只要你考虑树中的第二级作为根
答案 1 :(得分:9)
我做的唯一根节点只是将您的表PrimaryKey作为HierarchyId投射到您想要的锚记录上,例如
假设一个假装表有ArticleID | ArticleID_Parent |层次结构,你可以调整所有“根”以变得像这样独特;
UPDATE [Article]
SET Hierarchy=CAST('/'+CAST([ArticleID] as varchar(30))+'/' AS hierarchyid)
WHERE [ArticleID_Parent]=0
..然后获得特定根的“分支”;
SELECT * FROM [Article]
WHERE Article.Hierarchy.IsDescendantOf((SELECT Hierarchy FROM Article WHERE ArticleID=XXXX)) = 1
答案 2 :(得分:8)
是的,您正在阅读 - 使用HierarchyID只允许一个根节点。这就是它的方式,并且没有办法解决它,据我所知,没有引入一个人为的新“超级根”,除了允许你有几个第一级“子根”之外别无其他目的。 ...
马克
Greg(@ Greg0)已经指出更新 - 这个答案实际上是不正确的 - 请参阅他的回答了解更多细节。
答案 3 :(得分:6)
可用于表示层次结构中位置的hierarchyid数据类型。但它本身并不强制执行层次结构。这是hierarchyid的MSDN文档摘录。
由应用程序生成和分配hierarchyid值,以便行之间的所需关系反映在值中。
这个example显示了如何使用计算列和外键的组合来强制执行树。
CREATE TABLE Org_T3
(
EmployeeId hierarchyid PRIMARY KEY,
ParentId AS EmployeeId.GetAncestor(1) PERSISTED
REFERENCES Org_T3(EmployeeId),
LastChild hierarchyid,
EmployeeName nvarchar(50)
)
GO
在您的情况下,您将修改计算列公式,以便根记录Null(SQL Server中的Null值不强制使用外键)或者记录的未修改的hierarchyid(根将是他们自己的父级)将被退回。
这是上述示例的简化版本,其中包含为根节点分配null ParentId的策略。
create table Node
(
Id hierarchyid primary key,
ParentId AS case when Id.GetLevel() = 1 then
Null
else
Id.GetAncestor(1)
end PERSISTED REFERENCES Node(Id),
check (Id.GetLevel() != 0)
)
insert into Node (Id) values ('/1/');
insert into Node (Id) values ('/1/1/');
insert into Node (Id) values ('/'); --Fails as the roots will be at level 1.
insert into Node (Id) values ('/2/1/'); --Fails because the parent does not exist.
select Id.ToString(), ParentId.ToString() from Node;
只有上面的有效插入成功。
ID ParentId
/ 1 / NULL
/ 1/1 / / 1 /
答案 4 :(得分:3)
Yes you can have multiple roots.
There is no database engine restriction on multiple roots. But of course you need a discriminator when selecting. Consider the following which uses 'Division' as the discriminator:
CREATE TABLE [EmployeeOrg](
[OrgNode] [hierarchyid] NOT NULL,
[OrgLevel] AS ([OrgNode].[GetLevel]()),
[EmployeeID] [int] NOT NULL,
[Title] [varchar](20) NULL,
[Division] [int] not null
) ON [PRIMARY]
GO
Insert into EmployeeOrg (OrgNode, EmployeeID, Title, Division) values ('/', 1, 'Partner A', 1 );
Insert into EmployeeOrg (OrgNode, EmployeeID, Title, Division) values ('/1/', 2, 'Part A Legal', 1 );
Insert into EmployeeOrg (OrgNode, EmployeeID, Title, Division) values ('/1/1/', 3, 'Part A Legal Asst', 1 );
Insert into EmployeeOrg (OrgNode, EmployeeID, Title, Division) values ('/', 4, 'Partner B', 2 );
Insert into EmployeeOrg (OrgNode, EmployeeID, Title, Division) values ('/1/', 5, 'Partner B Legal', 2 );
Insert into EmployeeOrg (OrgNode, EmployeeID, Title, Division) values ('/1/1/', 6, 'Partner B Legal Asst', 2 );
SELECT *
FROM EmployeeOrg
WHERE OrgNode.IsDescendantOf('/') = 1 and Division = 1
SELECT *
FROM EmployeeOrg
WHERE OrgNode.IsDescendantOf('/') = 1 and Division = 2
This returns the two different hierarchies as expected.
答案 5 :(得分:2)
你不能只有一个'非显示'的根,并且所有主要文章都在1级?