Şimdi Hierarchyid veri tipimizi daha iyi anlayabilmek için hayali bir şirketin,organizasyon şemasını oluşturalım.

Şekildeki gibi bir organizasyon şemasına sahip şirketimizin;yönetim yapısını SQL Serverda ,yeni hierarchyid tipini kullanarak saklamak isteyelim.Önce Sirket isimli veri tabanımızı oluşturuyoruz,daha sonra Calisanlar isimli tablomuzu oluşturuyoruz.
Bundan sonrasında yazacağım sorgularla,şirketimizin hiyerarşik yapısını adım adım oluşturacağım.Yukarda ki organizasyon şeması şirket yapısını daha iyi anlamanız içindir.
CREATE TABLE Calisanlar
(Dugum hierarchyid PRIMARY KEY CLUSTERED,
Basamak AS dugum.GetLevel() PERSISTED,
Calisan_ID INT UNIQUE,
Calisan_Isim VARCHAR(30) NOT NULL)
Burada ast-üst ilişkisinin SQL Server’a aktarılmasını sağlayan fonksiyonumuz GetLevel() dir.Bu fonksiyonumuz herbir basamakta ki,düğümün değerini döndürür.Örneğin kök(root) düğümün,Ahmet,Basamak değeri 0 dır.Erdem ve Ali’nin;basamak değeri 1 dir ve aşağılara indikçe basamak değerinin artmasından dolayı da en son basamaktaki,Ada ve Cemil’in,basamak değerleri 3 olarak ifade edilecektir.
Tabloyu oluşturduktan sonra kök de(root) beraberinde oluşturulmuş olur.
INSERT INTO Calisanlar VALUES (hierarchyid::GetRoot(),5000,'Ahmet')
GetRoot() fonksiyonumuzsa,root‘un bulunduğu düğümdeki değeri döndürecek bir başka fonksiyonumuzdur.Burada Calisan_ID sinin değeri 5000 ‘den başlarken, basamaklar 0’dan başlayarak artacaktır.Bu iki ifadeyi birbirine karıştırmamamız gerekir.
Elinizde root düğüm varsa organizasyonel şemanızı oluşturmaya başlayabilirsiniz demektir.Ahmet’in(root’un),altında çalışanları tanımlayabilmek için GetDescendants fonksiyonunu kullanacağız.Bu fonksiyon ana bir düğümden türeyen düğümleri,child nodeları, döndürmektedir.
Bu örneğimiz için ilk düğümü döndürecektir.
--Öncelikle dügümlerde tutulacak gecici degiskenler tanımlayalım.
DECLARE @YoneticiDugum hierarchyid
DECLARE @Sira hierarchyid
--Kok dugum,"Ahmet", icin ,Calisan_ID 5000 dir.
SELECT @YoneticiDugum=Dugum FROM Calisanlar WHERE Calisan_ID=5000
--GetDescendant ilk dugumu bize dondurecektir.Ilk dugum "/1"
INSERT INTO Calisanlar VALUES (@YoneticiDugum.GetDescendant(NULL, NULL),5001, 'Ali')
Bu örneğimizde kök düğüm,Ahmet, basamak 0 dır ve “/ ” ile temsil edilir.Aynı şekilde Ahmet’in altında çalışan Ali;basamak 1 dir ve Ahmet’den sonra en kıdemli kişidir, “/1” ile temsil edilir.Aynı şekilde Erdem’i de yapımıza eklediğimizde değeri “/2” olacaktır.
--Kok dugum,"Ahmet", icin ,Calisan_ID 5000 dir.
SELECT @YoneticiDugum=Dugum FROM Calisanlar WHERE Calisan_ID=5000
--GetDescendant ilk dugumu bize dondurecektir.Ilk dugum "/1"
INSERT INTO Calisanlar VALUES (@YoneticiDugum.GetDescendant(NULL, NULL),5001, 'Ali')
--Ali'nin Calisan_ID di 5001 olacaktır.
SELECT @Sira=Dugum FROM Calisanlar WHERE Calisan_ID=5001
--Biz burada GetDescendant fonksiyonunu (Ali,NULL)olarak tanımlamış oluyoruz.
--Eğer tam tersi bir şekilde (NULL,Ali) olarak tanımlasaydık,
--Ali'den sonra düğümler ekleyemeyecektik.
INSERT INTO Calisanlar VALUES
(@YoneticiDugum.GetDescendant(@Sira, NULL),5002, 'Erdem')
İsterseniz,şu ana kadarki oluşturduğumuz şirketimizin, hiyerarşik yapısını sorgulayalım
SELECT Dugum.ToString() AS Dugumun_Text_Gosterimi,
Dugum AS Dugumun_Binary_Gosterimi,
Dugum.GetLevel() AS Sira,
Calisan_ID,
Calisan_Isim
FROM Calisanlar

Şirketimizin Organizasyon Şemasındaki,Dugumlerin yerleşimi ise şöyle olacaktır.

Şekilde de görüldüğü gibi Bilgehan,Erdem’in yöneticiliğinde çalışmaktadır ve düğümsel değeri “/2/1” dir.
SQL kodlarımızla şirketimizin organizasyon şemasını tamamlayalım.
SELECT @Sira=Dugum FROM Calisanlar WHERE Calisan_ID=5002
INSERT INTO Calisanlar VALUES(@Sira.GetDescendant(NULL, NULL),5003, 'Bilgehan')
--Erdem, yönetici olarak @Sira değişkeninde saklanıyor.
-- Bilgehan'ı ,Erdem altında çalışan biri olarak tanımladık.
DECLARE @dugum1 hierarchyid
--Bilgehan'ın,Calisan_ID si 5003 dür.
SELECT @dugum1=Dugum FROM Calisanlar WHERE Calisan_ID=5003
--GetDescendant,Bilgehan'dan sonraki Dugum 'ü döndürecek.
INSERT INTO Calisanlar VALUES (@Sira.GetDescendant(@dugum1, NULL),5004, 'Aydin')
--Şimdi de Aynı işlemleri Ali'nin Düğümü icin @Sira değişkeniyle gerçekleştiriyoruz.
SELECT @Sira=Dugum FROM Calisanlar WHERE Calisan_ID=5001
--Ali'den türeyen bir düğüm yoktu(NULL,NULL).Şimdi Ali'den sonra Selen düğümünü oluştuyoruz.
INSERT INTO Calisanlar VALUES (@Sira.GetDescendant(NULL,NULL),5005, 'Selen')
--Selen'in Dugum 'ü oluşturuldu.
SELECT @dugum1=Dugum FROM Calisanlar WHERE Calisan_ID=5005
--Tomris'i de Ali'nin yöneticiliğine atıyoruz.
INSERT INTO Calisanlar VALUES (@Sira.GetDescendant(@dugum1,NULL),5006, 'Tomris')
--Ada' da Tomris'in yöneticiliğinde
SELECT @Sira=Dugum FROM Calisanlar WHERE Calisan_ID=5006
--Ada'yı da Tomris'den sonra ki ilk yetkili yapıyoruz.
INSERT INTO Calisanlar VALUES (@Sira.GetDescendant(NULL,NULL),5007, 'Ada')
--Ada'nın Dugum 'ü olusturuldu.
SELECT @dugum1=Dugum FROM Calisanlar WHERE Calisan_ID=5007
--Cemil'i de ,Tomris'in yöneticiliğine sokuyoruz.
INSERT INTO Calisanlar VALUES (@Sira.GetDescendant(@dugum1,NULL),5008, 'Cemil')
Organizasyon şemamızı sorguladığımızda yapımız şöyle olmalıdır.

Diyelim ki organizasyonel yapımızda bir değişikliğe gidilmek zorunda kalındı ve Tomris ,Ali’nin ekibinden ayrılıp Aydın’ın ekibine dahil oldu.Böyle bir durum da ne olacak peki ? Tüm bu organizasyonel şema baştan mı oluşturulacak ? Tabii ki Hayır :=)
İşte bu tür;hiyerarşik yapıdaki değişiklikler için, GetReparentedValue() fonksiyonu kullanılmalıdır. (SQL Server 2008 RC0 ‘dan itibaren Reparent() fonksiyonu,GetReparentedValue() olarak değiştirilmiştir)
DECLARE @Basamak hierarchyid
DECLARE @EskiYonetici hierarchyid
DECLARE @YeniYonetici hierarchyid
SELECT @Basamak=Dugum from Calisanlar where Calisan_ID=5006 -- Tomris
SELECT @EskiYonetici=Dugum from Calisanlar where Calisan_ID=5001 -- Ali artık Tomris'i yönetmeyecek.
SELECT @YeniYonetici=Dugum from Calisanlar where Calisan_ID =5004 -- Aydın artık Tomris'in yöneticisi
UPDATE Calisanlar
SET Dugum = @Basamak.GetReparentedValue(@EskiYonetici, @YeniYonetici)
WHERE Dugum = @Basamak
Tablomuzun son haline bakarsak,aşağıdaki gibi değiştiğini göreceksiniz

Görüldüğü gibi;Tomris artık Aydın tarafından yönetilen bir çalışan.
Burada dikkatinizi çektiyse,küçük bir problemle karşı karşıyayız.Şöyle ki Tomris artık Ali tarafından yönetilmekten çıkıp Aydın tarafından yönetilmekte fakat Tomris’in yönettiği çalışanlar yöneticisiz kalmış durumda. ( “/1/2” şeklinde bir düğüm artık bulunmamakta)
Böyle bir durum sıkıntı yaratacaksa,geliştiriciler olarak duruma müdahale edilmeli ve indexler oluşturulmalıdır.Bu örnek için, 2 tür index tanımlaması yapılabilir.İlki Depth-First Index’dir ve bu index yapısında bütün düğümler,yanyana dizilir,birlikte saklanır ve istenilen özel bir düğüme bağlanabilir.Bütün çalışanların sadece bir yöneticiye bağlı olarak çalıştığı yapılarda kullanılabilir.

İkinci index türümüz ise;Breadth-First Index’dir.Bu index türünde bütün düğümler,dereceleriyle birlikte sıralı olarak tutulur.Aynı yöneticiye bağlı çalışanlar birlikte tutulurlar

Bir tablo oluşturulduktan sonra,depth first index,direk olarak primary key ile tanımlanmış olur.(Yani default olarak depth first index tanımlanmıştır.)Breadth-First Index tanımlamasını ise şöyle bir komutla biz yapabiliriz
CREATE Index Breadth on Calisanlar(Dugum,Basamak)
Bu makalemizde SQL Server 2008 ‘in yeni veri tiplerinden olan Hierarchyid Veri Tiplerini ve kullandığı fonksiyonlarını,örnek sorgularla inceledik.Bu makaleye bağlı makalelerde SQL Server 2008 ile gelen yeni veri tiplerini incelemeye devam edeceğiz.
Başka bir Microsoft SQL Server 2008 makalesinde görüşmek dileğiyle...
Bilgehan Gürünlüwww.gurunlu.com
bilgehan@gurunlu.com
Kaynaklar :-http://msdn.microsoft.com/en-us/library/
-Accelerated SQL Server 2008
-Programming Microsoft® SQL Server 2008 (Ms-Press)
- SQL Server TechCenter