TSql HierarchyID 数据类型用法(sqlserver2008以上有此数据类型)

TSql HierarchyID 数据类型用法

2017年04月25日 09:47:46

阅读数:110

HierarchyID 数据类型是一种长度可变的系统数据类型。可使用 HierarchyID 表示层次结构中的位置。类型为 HierarchyID 的列不会自动表示树,由应用程序来生成和分配 HierarchyID 值,使行与行之间的所需关系反映在这些值中。

1,字符串表示

必须以“/”开头,以“/”结尾,“/”之间使用数值标识某一个元素,一般是整数或小数,例如“/”,“/1/2/”,“/1/2/3/”,"/1/2/3.1"

2,数据类型的转换

declare @sa Nvarchar(100)
declare @ha HierarchyID
declare @hb HierarchyID

set @sa=‘/1/2/3/‘
set @ha=HierarchyID::Parse(@sa)
set @hb=0x5B5E

select @sa as sa,@ha as ha,@hb.ToString() as hb

3,按深度优先顺序进行比较

给定两个 hierarchyid 值 a 和 b,a<b 表示在对树进行深度优先遍历时,先找到 a,后找到 b。hierarchyid  数据类型的索引按深度优先顺序排序,在深度优先遍历中相邻的节点的存储位置也相邻。同Level的节点,左边节点小于右边节点,表示左边先被遍历到。

declare @sa Nvarchar(100)
declare @sb Nvarchar(100)
declare @ha HierarchyID
declare @hb HierarchyID

set @sa=‘/1/2/3/‘
set @sb=‘/1/2/‘

set @ha=HierarchyID::Parse(@sa)
set @hb=HierarchyID::Parse(@sb)

if @ha>[email protected]
print @sa+‘>=‘[email protected]
else
print @sa+‘<‘[email protected]

4,调用GetLevel()查看HierarchyID的Level,值是从root节点开始的层数。

declare @sa Nvarchar(100)
declare @ha HierarchyID

set @sa=‘/1/2/3/‘
set @ha=HierarchyID::Parse(@sa)

select @sa as sa,@ha as ha,@ha.GetLevel() as Level

5,静态方法GetRoot(),静态方法的调用格式:HierarchyID::GetRoot()

select HierarchyID::GetRoot().ToString() as TootString,HierarchyID::GetRoot() as RootHierarchyID

6,GetDescendant(childleft,childright)用以返回父级的一个子节点,返回的子节点和child是同level的。

declare @sa Nvarchar(100)
declare @sb Nvarchar(100)
declare @sr Nvarchar(100)
declare @ha HierarchyID
declare @hb HierarchyID
declare @hr HierarchyID

set @sa=‘/1/2/3/‘
set @sb=‘/1/2/6/‘
set @sr=‘/1/2/‘
set @ha=HierarchyID::Parse(@sa)
set @hb=HierarchyID::Parse(@sb)
set @hr=HierarchyID::Parse(@sr)

select  @hr.GetDescendant(null,null).ToString(),
        @hr.GetDescendant(@ha,null).ToString(),
        @hr.GetDescendant(@ha,@hb).ToString()

如果LeftChild是‘/1/2/3’,RightChild是‘/1/2/4’,需要在这两个节点之间插入一个新的节点,需要如何处理?表示节点的数字,并不一定必须是正整数,小数也可以,如下,NewChild=’/1/2/3.1/‘;

declare @sa Nvarchar(100)
declare @sb Nvarchar(100)
declare @sr Nvarchar(100)
declare @ha HierarchyID
declare @hb HierarchyID
declare @hr HierarchyID

set @sa=‘/1/2/3/‘
set @sb=‘/1/2/4/‘
set @sr=‘/1/2/‘
set @ha=HierarchyID::Parse(@sa)
set @hb=HierarchyID::Parse(@sb)
set @hr=HierarchyID::Parse(@sr)

select    @hr.GetDescendant(null,null).ToString(),
        @hr.GetDescendant(@ha,null).ToString(),
        @hr.GetDescendant(@ha,@hb).ToString()

7,判断是否是节点的后代,child.IsDescendantOf(parent),如果是,返回1,如果不是,返回0

declare @sa Nvarchar(100)
declare @sb Nvarchar(100)
declare @sr Nvarchar(100)
declare @ha HierarchyID
declare @hb HierarchyID
declare @hr HierarchyID

set @sa=‘/1/2/3/‘
set @sb=‘/1/2/6/‘
set @sr=‘/1/2/‘
set @ha=HierarchyID::Parse(@sa)
set @hb=HierarchyID::Parse(@sb)
set @hr=HierarchyID::Parse(@sr)

select    @ha.IsDescendantOf(@hr),
        @hb.IsDescendantOf(@hr),
        @ha.IsDescendantOf(@hb)

8,更新HierarchyID的值,必须级联地更新与该节点相关的子节点的值,这是由于HierarchyID类型自身的局限性导致的。

hierarchyid 数据类型具有以下局限性:

  • 类型为 hierarchyid 的列不会自动表示树。由应用程序来生成和分配 hierarchyid 值,使行与行之间的所需关系反映在这些值中。 某些应用程序可能具有 hierarchyid 类型的列,该列指示在另一个表中定义的层次结构中的位置。
  • 由应用程序来管理生成和分配 hierarchyid 值时的并发情况。不能保证列中的 hierarchyid 值是唯一的,除非应用程序使用唯一键约束或应用程序自身通过自己的逻辑来强制实现唯一性。
  • 由 hierarchyid 值表示的层次结构关系不是像外键关系那样强制实现的。  可能会出现下面这种层次结构关系而且有时这种关系是合理的:A 具有子级 B,然后删除了 A,导致 B 与一条不存在的记录之间存在关系。 如果这种行为不可接受,应用程序在删除父级之前必须先查询其是否有后代

8.1 ,创建数据源

create table dbo.emph2
(
idpath hierarchyid not null primary key,
id int not null,
parentid as idpath.GetAncestor(1) persisted foreign key references dbo.emph2(idpath),
descr varchar(100)
)

idpath=’/1/2/6/‘的子孙节点如下图

select e.idpath.ToString() as IDPath,e.id,e.parentid.ToString() as ParentIDPath,e.descr
from dbo.emph2 e
where e.idpath.IsDescendantOf(HierarchyID::Parse(‘/1/2/6/‘))=1

8.2,子节点变更为另一个父节点,例如将idpath=’/1/2/6/‘ 的节点删除,并将其子节点的父节点变更为idpath=’/1/2/7/‘

由于存在外键关系,必须先变更子节点的父节点,然后再删除idpath=’/1/2/6/‘ 的节点。

--delete child notes
--select e.idpath.ToString() as IDPath,e.id,e.parentid.ToString() as ParentIDPath,e.descr
update e set e.idpath=HierarchyID::Parse(‘/1/2/7/‘+cast(e.id as varchar)+‘/‘)
from dbo.emph2 e
where e.idpath.IsDescendantOf(HierarchyID::Parse(‘/1/2/6/‘))=1 and e.idpath!=HierarchyID::Parse(‘/1/2/6/‘)

--delete parent note
delete dbo.emph2 where idpath=HierarchyID::Parse(‘/1/2/6/‘)

--check
select e.idpath.ToString() as IDPath,e.id,e.parentid.ToString() as ParentIDPath,e.descr
from dbo.emph2 e
where e.idpath.IsDescendantOf(HierarchyID::Parse(‘/1/2/7/‘))=1

8.3,将idpath=’/1/2/6/‘的节点的父节点变更,其子节点仍然是其子节点。

思路是新建一个节点,并将子节点都挂在新节点下。

--create new node
insert into dbo.emph2(idpath,id,descr)
select HierarchyID::Parse(‘/1/3/6/‘),id,descr
from dbo.emph2 e
where e.idpath=HierarchyID::Parse(‘/1/2/6/‘)

--delete child notes
--select e.idpath.ToString() as IDPath,e.id,e.parentid.ToString() as ParentIDPath,e.descr
update e set e.idpath=HierarchyID::Parse(‘/1/3/6/‘+cast(e.id as varchar)+‘/‘)
from dbo.emph2 e
where e.idpath.IsDescendantOf(HierarchyID::Parse(‘/1/2/6/‘))=1 and e.idpath!=HierarchyID::Parse(‘/1/2/6/‘)

--delete parent note
delete dbo.emph2 where idpath=HierarchyID::Parse(‘/1/2/6/‘)

--check
select e.idpath.ToString() as IDPath,e.id,e.parentid.ToString() as ParentIDPath,e.descr
from dbo.emph2 e
where e.idpath.IsDescendantOf(HierarchyID::Parse(‘/1/3/6/‘))=1

8.4 定向插入新的节点,由于节点之间存在先后顺序,使用GetDescendant(ChildLeft,ChildRight)保证顺序。

在节点 idpath=’/1/2/6/‘ 的子节点 id=15,id=16之间插入一个新的子节点,新的子节点的id=36,descr=‘E1136’,思路是使用GetDescendant(ChildLeft,ChildRight)获取新的IDPath,然后插入到表中。

declare @id int
declare @descr Nvarchar(100)
declare @sa Nvarchar(100)
declare @sb Nvarchar(100)
declare @sr Nvarchar(100)
declare @hnew HierarchyID

set @id=36
set @descr=‘E1136‘
set @sa=‘/1/2/6/15/‘
set @sb=‘/1/2/6/16/‘
set @sr=‘/1/2/6/‘

set @hnew= HierarchyID::Parse(@sr).GetDescendant(HierarchyID::Parse(@sa),HierarchyID::Parse(@sb))

insert into dbo.emph2(idpath,id,descr)
values(@hnew,@id,@descr)

select e.idpath.ToString() as IDPath,e.id,e.parentid.ToString() as ParentIDPath,e.descr
from dbo.emph2 e
where e.idpath.IsDescendantOf(HierarchyID::Parse(‘/1/2/6/‘))=1
order by e.idpath

从排序的结果集中可以看出,id=36的节点,处于id=15和id=16的节点之间,通过GetDescendant(ChildLeft,ChildRight)实现了顺序。

9, HierarchyID类型的数据,很容易实现广度优先遍历和深度优先遍历

9.1,广度优先遍历是指查询层次结构中相同级别的节点

select idpath.ToString() as IDPath,id,parentid.ToString() as ParentIDPath,descr
from dbo.emph2 where idpath.GetLevel()=2

9.2,深度优先遍历是指遍历一个节点的所有子节点

select idpath.ToString() as IDPath,id,parentid.ToString() as ParentIDPath,descr
from dbo.emph2
where idpath.IsDescendantOf(HierarchyID::Parse(‘/1/2/6/‘))=1

原文地址:https://www.cnblogs.com/weiyu11/p/9249361.html

时间: 2024-10-09 23:03:18

TSql HierarchyID 数据类型用法(sqlserver2008以上有此数据类型)的相关文章

T-SQL函数及用法--转

转自http://www.cnblogs.com/qixuejia/archive/2010/07/14/1777105.html 1. 聚合函数 (1) AVG 函数功能返回组中值的平均值.空值将被忽略 语法AVG ( [ ALL | DISTINCT ] expression ) (2) MAX 函数功能返回表达式的最大值 语法MAX ( [ ALL | DISTINCT ] expression ) (3) MIN 函数功能返回表达式的最小值 语法MIN ( [ ALL | DISTINC

TSql HierarchyID 数据类型用法

HierarchyID 数据类型是一种长度可变的系统数据类型.可使用 HierarchyID 表示层次结构中的位置.类型为 HierarchyID 的列不会自动表示树,由应用程序来生成和分配 HierarchyID 值,使行与行之间的所需关系反映在这些值中. 1,字符串表示 必须以“/”开头,以“/”结尾,“/”之间使用正整数标识某一个元素,例如“/”,“/1/2/”,“/1/2/3/” 2,数据类型的转换 declare @sa Nvarchar(100) declare @ha Hierar

JAVA自定义数据类型用法

一,自定义数据类型的概念:    我们就拿一部手机进行分析,它能用来做什么呢?它可以打电话,上网,聊微信等,这些就是 手机所提供的功能,也就是方法:手机也有它的特征,如颜色.尺寸大小.品牌型号等,这些    就 是手机的特征,也就是属性. 二,自定义数据类型的定义方法:    pubilc class 类名    {        数据类型 属性名;        数据类型 属性名;    } 注意:创建的java文件博需和类型相同. 三,自定义数据类型的使用 创建方法     数据类型 变量名

T-SQL Apply的用法

SQL Server 2005 新增 cross apply 和 outer apply 联接语句,增加这两个东东有啥作用呢? 我们知道有个 SQL Server 2000 中有个 cross join 是用于交叉联接的.实际上增加 cross apply 和 outer apply 是用于交叉联接表值函数(返回表结果集的函数)的, 更重要的是这个函数的参数是另一个表中的字段.这个解释可能有些含混不请,请看下面的例子: -- 1. cross join 联接两个表 select * from T

sQLserver T-SQL 事务的用法

原文在: https://www.lesg.cn/netdaima/2016-55.html 在使用Mssql的时候经常需要用到存储过程 有些操作在前面发生错误的时候:需要回滚:这就需要事务了: 下面是代码: BEGIN TRANSACTION--开始事务 DECLARE @errorSun int=0 --定义错误计数器 DECLARE @ErrorMessage NVARCHAR(4000)=''; --DECLARE @Remark NVARCHAR(4000)='';--备注 BEGIN

TSql bulk insert 用法

语法,参见 MSDN URL:https://msdn.microsoft.com/zh-cn/library/ms188365.aspx BULK INSERT [ database_name . [ schema_name ] . | schema_name . ] [ table_name | view_name ] FROM 'data_file' [ WITH ( [ [ , ] BATCHSIZE = batch_size ]    --BATCHSIZE指令来设置在单个事务中可以插

四类、八种基本数据类型,其他都是引用数据类型

第一类:整型 byte short int long 第二类:浮点型 float double 第三类:逻辑型 boolean(它只有两个值可取true false) 第四类:字符型 char 这四类八种基础数据类型 都在栈中直接分配内存空间,这些都是基础数据流类型,剩下的一切引用类型都存储在堆中,引用存储在栈中,数据存储 在堆中 引用指向堆中的数据,我说的这些可能大家 比较绕,做个比喻吧,把客厅比喻java的栈内存块,把卧室比如堆内存块,然后呢 电视机的遥控器也就是也就是电视机的引用放在客厅里

基本数据类型的值传递 和引用数据类型的引用传递 Day06

ValueTest1.java package com.sxt.valuetest; /* * 基本数据类型的传递:传递的是值得副本 */ public class ValueTest1 { public static void main(String[] args) { int num = 10; System.out.println("方法调用前:"+num);//10 changeValue(num); System.out.println("方法调用后:"+

Java基础(34):Java中基本数据类型的包装类(主要为了不同数据类型之间更方便的进行转换)

相信各位小伙伴们对基本数据类型都非常熟悉,例如 int.float.double.boolean.char 等.基本数据类型是不具备对象的特性的,比如基本类型不能调用方法.功能简单...,为了让基本数据类型也具备对象的特性, Java 为每个基本数据类型都提供了一个包装类,这样我们就可以像操作对象那样来操作基本数据类型. 基本类型和包装类之间的对应关系: 包装类主要提供了两大类方法: 1. 将本类型和其他基本类型进行转换的方法 2. 将字符串和本类型及包装类互相转换的方法 我们将在后面的小节逐步