SQL Server 使用 Hierarchyid 操作層次結構數據

来源:http://www.cnblogs.com/Brambling/archive/2017/04/27/6772123.html
-Advertisement-
Play Games

層次結構數據定義為一組通過層次結構關係互相關聯的數據項。 在層次結構關係中,一個數據項是另一個項的父級或子級。 sql server2008開始內置的 hierarchyid 數據類型使存儲和查詢層次結構數據變得更為容易。hierarchyid 其實是 CLR 數據類型。 廢話不多說,看不明白就實際 ...


層次結構數據定義為一組通過層次結構關係互相關聯的數據項。 在層次結構關係中,一個數據項是另一個項的父級或子級。

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()    -- GetLevel()用於確定當前層次的深度(級別),最頂層(根節點)為0,然後依次加1。
)
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    -- 因為 hierarchyid 類型的值是以16進位表示的,這裡把他轉換為字元串
from RoleMan

查詢指定節點的祖先節點:

-- 查詢指定節點的祖先節點
declare @NodeId    hierarchyid

select @NodeId=NodeId 
from RoleMan 
where RoleId=5

select *,NodeId.ToString() NodeId_Path 
from RoleMan 
where @NodeId.IsDescendantOf(NodeId)=1    -- IsDescendantOf(NodeId),判斷指定節點是否是另一個節點的後代,如果是,則返回1

查詢指定節點的子孫節點:

-- 查詢指定節點的子孫節點
declare @NodeId    hierarchyid

select @NodeId=NodeId
from RoleMan 
where RoleId=2

select *,NodeId.ToString() NodeId_Path 
from RoleMan 
where NodeId.IsDescendantOf(@NodeId)=1    -- IsDescendantOf(NodeId),判斷指定節點是否是另一個節點的後代,如果是,則返回1

返回指定層級的所有節點:

-- 返回指定層級的所有節點
declare @NodeId    hierarchyid

select @NodeId=NodeId
from RoleMan 
where Par_NodeId=1        -- 指定層級為 1 級

select @NodeId
select *,NodeId.ToString() NodeId_Path 
from RoleMan 
where NodeId.GetAncestor(0)=@NodeId    -- GetAncestor(0),會返回當前層級當前節點的數據

select @NodeId
select *,NodeId.ToString() NodeId_Path 
from RoleMan 
where NodeId.GetAncestor(1)=@NodeId    -- GetAncestor(1),會返回指定層級(@NodeId指定為1級)的下一級的所有節點的數據
                                    -- 數值 1 表示要在層次結構中下降的級別數。

插入新節點:

declare @PNodeId hierarchyid
declare @NodeId    hierarchyid

select @PNodeId=NodeId 
from RoleMan 
where RoleId=3        -- 獲取 管理員B 的節點,即用於為添加的節點指定父級

select @NodeId=NodeId 
from RoleMan 
where RoleId=7        -- 獲取 用戶BB 的節點,即指定添加的節點位於哪個子節點後面

insert into RoleMan(NodeId,RoleId,RoleName)  
values(@PNodeId.GetDescendant(@NodeId, NULL),'8','用戶BC')  --即在父節點為 '管理員B' 下麵的子節點 '用戶BB' 後面添加一個節點 '用戶BC'

select *,
NodeId.ToString() NodeId_Path    
from RoleMan

當然,這是父節點下麵存在著子節點的時候,那麼當父節點下麵沒有子節點應該怎麼添加呢?只需要將 GetDescendant(null,null) 的兩個參數都設置為null就行了。如下:

declare @PNodeId hierarchyid

select @PNodeId=NodeId 
from RoleMan 
where RoleId=8        -- 獲取 用戶BC 的節點,即用於為添加的節點指定父級

insert into RoleMan(NodeId,RoleId,RoleName)
values(@PNodeId.GetDescendant(null, NULL),'9','用戶BCA')    -- 為無子節點的父節點添加子節點

select *,
NodeId.ToString() NodeId_Path    
from RoleMan

如果需要在一個父節點下麵的兩個子節點之間插入一個子節點,就需要將 GetDescendant(@Child1,@Child2) 的兩個參數同時指定。如下:

declare @PNodeId hierarchyid
declare @Child1    hierarchyid
declare @Child2 hierarchyid

select @PNodeId=NodeId 
from RoleMan 
where RoleId=2        -- 獲取 管理員A 的節點,即用於為添加的節點指定父級

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插隊')-- 在父節點 管理員A 的子節點 用戶AA 和 用戶AB 之間插入一個節點 用戶A插隊

select *,
NodeId.ToString() NodeId_Path    
from RoleMan

變更節點位置:

變更節點位置應當使用 GetReparentedValue 方法,該方法接受兩個參數,一個是原節點的 hierarchyid,另一個是目標節點 hierarchyid。

-- 把 管理員B 節點下麵的子節點 用戶BA 移動到 管理員A 節點的子節點 用戶AB 後面
declare @RawNodePath hierarchyid
declare @NewNodePath hierarchyid

select @RawNodePath=NodeId  
from RoleMan 
where RoleId=6        -- 獲取節點 用戶BA 

select @NewNodePath=NodeId 
from RoleMan 
where RoleId=2        -- 獲取節點 管理員A

select @NewNodePath=@NewNodePath.GetDescendant(MAX(NodeId), NULL)    -- 獲取節點 管理員A 下麵的最大的子節點,即最後一個子節點
from RoleMan 
where NodeId.GetAncestor(1)=@NewNodePath    -- 獲取父節點 管理員A 下麵的所有子級

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

select *,
NodeId.ToString() NodeId_Path    
from RoleMan

go

 

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

廣度優先索引,是將層次結構中每個級別的各行存儲在一起,簡而言之,就是按層級排序的方式存儲。

創建廣度優先索引:

--創建廣度優先索引
create clustered index Role_Breadth_First   
on RoleMan(Par_NodeId,NodeId) ;  
go  

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

 

參考:

http://blog.csdn.net/zhanghongju/article/details/42584643

https://msdn.microsoft.com/zh-cn/library/bb677173.aspx

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 沒有偶然的運氣,只有不斷的努力! There is no accidental luck, only constant efforts! 首先 新聞發佈會結合了JSP里的Servlet和request對象,response對象還有使用session對象和cookie對象。 -登錄頁面 package ...
  • 【註】關閉window的防火牆 1. 安裝開發hadoop插件 將hadoop安裝包hadoop-eclipse-plugin-2.7.3拷貝到eclipse的插件目錄plugins下。 插件百度雲地址:http://pan.baidu.com/s/1dEXywz3 重啟eclipse,打開wind ...
  • R + Hive = RHive 支持原創:http://blog.fens.me/nosql-r-hive/ R利劍NoSQL系列文章 之 Hive Hive介紹 Hive安裝 RHive安裝 RHive函數庫 RHive基本使用操作 1. Hive介紹 Hive是建立在Hadoop上的數據倉庫基 ...
  • 在使用JDBC連接mysql時可能會遇到以下錯誤: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure The last packet sent successfully to th ...
  • 1. 忘記root密碼編輯mysql主配置文件 my.cnf 在[mysqld]欄位下添加參數 skip-grant ,重啟資料庫服務,這樣就可以進入資料庫不用授權了 mysql -uroot ,修改相應用戶密碼 use mysql; update user set password=passwor ...
  • 使用下麵的命令檢查是否安裝有MySQL Server 有的話,我們就通過 rpm -e 命令 或者 rpm -e --nodeps 命令來卸載掉 在刪除完以後我們可以通過 rpm -qa | grep mysql 命令來查看mysql是否已經卸載成功!! 官網yum repository 下載安裝包 ...
  • 背景 yarn預設使用的是最簡單的FIFO調度器,即一個default隊列,所有用戶共用,分配資源也是先到先得,沒有優先順序之分。有時一兩個任務就把資源全占了,其他任務吃不到資源造成饑餓,顯然這樣的資源分配是不合理的(在當今社會主義之中,我們要共同富裕啊)。yarn還有兩種資源調度器,capacity ...
  • 昨天收穫頗多,首先回顧一下有關mysql的內容。 我在查詢表信息時,出現了 empty set 0.00 sec 的錯誤,我很奇怪,仔細檢查發現原來是表欄位名稱寫錯了, 於是我想修改欄位名稱,經過查詢相關知識終於修改成功。 將表user 欄位 naem 修改為 name: ALTER TABLE u ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...