使用t-sql
层次结构ID 如何获取所有没有子代的行(即最后一个后代)?
假设我的表结构如下:
Id,
Name,
HierarchyId
并有这些行:
1, Craig, /
2, Steve, /1/
3, John, /1/1/
4, Sam, /2/
5, Matt, /2/1/
6, Chris, /2/1/1/
什么问题会给我约翰和克里斯?
使用t-sql
层次结构ID 如何获取所有没有子代的行(即最后一个后代)?
假设我的表结构如下:
Id,
Name,
HierarchyId
并有这些行:
1, Craig, /
2, Steve, /1/
3, John, /1/1/
4, Sam, /2/
5, Matt, /2/1/
6, Chris, /2/1/1/
什么问题会给我约翰和克里斯?
也许有更好的方法,但这个接缝可以完成这项工作。
declare @T table
(
ID int,
Name varchar(10),
HID HierarchyID
)
insert into @T values
(1, 'Craig', '/'),
(2, 'Steve', '/1/'),
(3, 'John', '/1/1/'),
(4, 'Sam', '/2/'),
(5, 'Matt', '/2/1/'),
(6, 'Chris', '/2/1/1/')
select *
from @T
where HID.GetDescendant(null, null) not in (select HID
from @T)
结果:
ID Name HID
----------- ---------- ---------------------
3 John 0x5AC0
6 Chris 0x6AD6
2012-05-22 更新
如果节点编号不是完整的序列,则上述查询将失败。这是另一个应该解决这个问题的版本。
declare @T table
(
ID int,
Name varchar(10),
HID HierarchyID
)
insert into @T values
(1, 'Craig', '/'),
(2, 'Steve', '/1/'),
(3, 'John', '/1/1/'),
(4, 'Sam', '/2/'),
(5, 'Matt', '/2/1/'),
(6, 'Chris', '/2/1/2/') -- HID for this row is changed compared to above query
select *
from @T
where HID not in (select HID.GetAncestor(1)
from @T
where HID.GetAncestor(1) is not null)
由于您只需要叶子并且不需要从特定的祖先获取它们,因此像这样的简单非递归查询应该可以完成工作:
SELECT * FROM YOUR_TABLE PARENT
WHERE
NOT EXISTS (
SELECT * FROM YOUR_TABLE CHILD
WHERE CHILD.HierarchyId = PARENT.Id
)
用简单的英语:选择没有子行的每一行。
这假设您HierarchyId
是指向 的外键Id
,而不是您的示例中显示的整个“路径”。如果不是,这可能是您应该在数据库模型中修复的第一件事。
- - 编辑 - -
好的,这是实际有效的 MS SQL Server 特定查询:
SELECT * FROM YOUR_TABLE PARENT
WHERE
NOT EXISTS (
SELECT * FROM YOUR_TABLE CHILD
WHERE
CHILD.Id <> PARENT.Id
AND CHILD.HierarchyId.IsDescendantOf(PARENT.HierarchyId) = 1
)
请注意, 将IsDescendantOf
任何行视为其自身的后代,因此我们还需要CHILD.Id <> PARENT.Id
条件中的 。
嗨,我使用这个,非常适合我。
CREATE TABLE [dbo].[Test]([Id] [hierarchyid] NOT NULL, [Name] [nvarchar](50) NULL)
DECLARE @Parent AS HierarchyID = CAST('/2/1/' AS HierarchyID) -- Get Current Parent
DECLARE @Last AS HierarchyID
SELECT @Last = MAX(Id) FROM Test WHERE Id.GetAncestor(1) = @Parent -- Find Last Id for this Parent
INSERT INTO Test(Id,Name) VALUES(@Parent.GetDescendant(@Last, NULL),'Sydney') -- Insert after Last Id