设为首页 收藏本站
查看: 1194|回复: 0

[经验分享] SQL Server 使用 Hierarchyid 操作层次结构数据

[复制链接]

尚未签到

发表于 2017-12-14 11:03:45 | 显示全部楼层 |阅读模式
  层次结构数据定义为一组通过层次结构关系互相关联的数据项。 在层次结构关系中,一个数据项是另一个项的父级或子级。
  sql server2008开始内置的 hierarchyid 数据类型使存储和查询层次结构数据变得更为容易。hierarchyid 其实是 CLR 数据类型。
  废话不多说,看不明白就实际操作一把,然后再回过头来理解。
  下面先创建一个表,并插入一些数据:
  

create table RoleMan  
(
  NodeId    hierarchyid
not null,  RoleId   
int not null,  RoleName   
nvarchar(32) not null,  Par_NodeId   
as NodeId.GetLevel()  
)
  
go
  

  
insert into RoleMan(NodeId,RoleId,RoleName)
  
select '/1/','1','超级管理员' union
  
select '/1/1/','2','管理员A' union
  
select '/1/2/','3','管理员B' union
  
select '/1/1/1/','4','用户AA' union
  
select '/1/1/2/','5','用户AB' union
  
select '/1/2/1/','6','用户BA' union
  
select '/1/2/2/','7','用户BB'
  
go
  

  
select *,
  
NodeId.ToString() NodeId_Path   
  
from RoleMan
  

DSC0000.png

  查询指定节点的祖先节点:
  

  
declare @NodeId    hierarchyid
  

  
select @NodeId=NodeId
  
from RoleMan
  
where RoleId=5
  

  
select *,NodeId.ToString() NodeId_Path
  
from RoleMan
  
where @NodeId.IsDescendantOf(NodeId)=1   
  

DSC0001.png

  查询指定节点的子孙节点:
  

  
declare @NodeId    hierarchyid
  

  
select @NodeId=NodeId
  
from RoleMan
  
where RoleId=2
  

  
select *,NodeId.ToString() NodeId_Path
  
from RoleMan
  
where NodeId.IsDescendantOf(@NodeId)=1   
  

DSC0002.png

  返回指定层级的所有节点:
  

  
declare @NodeId    hierarchyid
  

  
select @NodeId=NodeId
  
from RoleMan
  
where Par_NodeId=1        
  

  
select @NodeId
  
select *,NodeId.ToString() NodeId_Path
  
from RoleMan
  
where NodeId.GetAncestor(0)=@NodeId   
  

  
select @NodeId
  
select *,NodeId.ToString() NodeId_Path
  
from RoleMan
  
where NodeId.GetAncestor(1)=@NodeId   
  

DSC0003.png

  插入新节点:
  

declare @PNodeId hierarchyid  

declare @NodeId    hierarchyid  

  

select @PNodeId=NodeId  

from RoleMan  

where RoleId=3  

  
select @NodeId=NodeId
  
from RoleMan
  
where RoleId=7        
  

  
insert into RoleMan(NodeId,RoleId,RoleName)  
  
values(@PNodeId.GetDescendant(@NodeId, NULL),'8','用户BC')  --即在父节点为 '管理员B' 下面的子节点 '用户BB' 后面添加一个节点 '用户BC'
  

  
select *,
  
NodeId.ToString() NodeId_Path   
  
from RoleMan
  

DSC0004.png

  当然,这是父节点下面存在着子节点的时候,那么当父节点下面没有子节点应该怎么添加呢?只需要将 GetDescendant(null,null) 的两个参数都设置为null就行了。如下:
  

declare @PNodeId hierarchyid  

  

select @PNodeId=NodeId  

from RoleMan  

where RoleId=8  

  
insert into RoleMan(NodeId,RoleId,RoleName)
  
values(@PNodeId.GetDescendant(null, NULL),'9','用户BCA')   
  

  
select *,
  
NodeId.ToString() NodeId_Path   
  
from RoleMan
  

DSC0005.png

  如果需要在一个父节点下面的两个子节点之间插入一个子节点,就需要将 GetDescendant(@Child1,@Child2) 的两个参数同时指定。如下:
  

declare @PNodeId hierarchyid  

declare @Child1    hierarchyid  

declare @Child2 hierarchyid  

  

select @PNodeId=NodeId  

from RoleMan  

where RoleId=2  

  
select @Child1=NodeId  
  
from RoleMan
  
where RoleId=4        
  

  
select @Child2=NodeId  
  
from RoleMan
  
where RoleId=5        
  

  
insert into RoleMan(NodeId,RoleId,RoleName)
  
values(@PNodeId.GetDescendant(@Child1, @Child2),'10','用户A插队')
  

  
select *,
  
NodeId.ToString() NodeId_Path   
  
from RoleMan
  

DSC0006.png

  变更节点位置:
  变更节点位置应当使用 GetReparentedValue 方法,该方法接受两个参数,一个是原节点的 hierarchyid,另一个是目标节点 hierarchyid。
  

  
declare @RawNodePath hierarchyid
  
declare @NewNodePath hierarchyid
  

  
select @RawNodePath=NodeId  
  
from RoleMan
  
where RoleId=6        
  

  
select @NewNodePath=NodeId
  
from RoleMan
  
where RoleId=2        
  

  
select @NewNodePath=@NewNodePath.GetDescendant(MAX(NodeId), NULL)   
  
from RoleMan
  
where NodeId.GetAncestor(1)=@NewNodePath   
  

  
update RoleMan
  
set NodeId=NodeId.GetReparentedValue(@RawNodePath, @NewNodePath)
  
where NodeId.IsDescendantOf(@RawNodePath) = 1
  

  
select *,
  
NodeId.ToString() NodeId_Path   
  
from RoleMan
  

  
go
  

DSC0007.png

  hierarchyid 函数:
  GetLevel():用于确定当前层次的深度(级别),最顶层(根节点)为0,然后依次加1。
  ToString():因为 hierarchyid 类型的值是以16进制表示的,ToString()用于将 hierarchyid 类型转换为字符串类型。
  IsDescendantOf():判断指定节点是否是另一个节点的后代,如果是,则返回1。一个参数,为指定的节点。
  GetAncestor(n):n=0时,会返回当前层级当前节点的数据。否则,会返回指定层级的下 n 级的所有节点。
  GetDescendant(null,null) :用于添加节点,该方法接受两个参数,可为空,第一个子节点,第二个子节点。如果第一个参数不为空,表示在指定的父节点下面的子节点后面添加节点,如果两个参数皆为空,则表示要在没有子节点的节点添加节点。
  GetReparentedValue():用于变更节点位置,该方法接受两个参数,一个是原节点的hierarchyid,另一个是目标节点hierarchyid。
  GetRoot():获取节点的根。
  Parse():将字符串转换为 hierarchyid 。该字符串的格式通常都是/1/这样的。
  Read():Read 从传入的 BinaryReader 读取 SqlHierarchyId 的二进制表示形式,并将 SqlHierarchyId 对象设置为该值。不能使用 Transact-SQL 调用 Read。请改为使用 CAST 或 CONVERT。
  Write():Write 将 SqlHierarchyId 的二进制表示形式写出到传入的 BinaryWriter 中。无法通过使用 Transact-SQL 来调用 Write。请改为使用 CAST 或 CONVERT。
  hierarchyid 索引策略:
  用于对层次结构数据进行索引的策略有两种:深度优先和广度优先。
  深度优先索引,子树中各行的存储位置相邻,简而言之,就是以 hierarchyid 值排序的方式存储。
  创建深度优先索引:
  

  
create unique index Role_Depth_First
  
on RoleMan(NodeId)
  
go
  

  
select *,NodeId.ToString() NodeId_Path
  
from RoleMan
  
order by NodeId
  

DSC0008.png

  广度优先索引,是将层次结构中每个级别的各行存储在一起,简而言之,就是按层级排序的方式存储。
  创建广度优先索引:
  

  
create clustered index Role_Breadth_First   
  
on RoleMan(Par_NodeId,NodeId) ;  
  
go  
  

  
select *,NodeId.ToString() NodeId_Path
  
from RoleMan
  
order by Par_NodeId,NodeId
  

DSC0009.png

  参考:
  http://blog.csdn.net/zhanghongju/article/details/42584643
  https://msdn.microsoft.com/zh-cn/library/bb677173.aspx

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-423959-1-1.html 上篇帖子: sql server 2008 R2 升级与安装遇到的问题 下篇帖子: Spring JDBCTemplate连接SQL Server之初体验
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表