Makale Özeti

Bu makalemizde SQL Server 2008 ‘in yeni veri tiplerinden olan Hierarchyid Veri Tiplerini ve kullandığı fonksiyonlarını,örnek sorgularla inceleyeceğiz

Makale

SQL Server 2008 ile birlikte gelen birçok yenilikten biri de,yeni veri tipleridir.SQL Server 2008’de daha önceki sürümlerde kullandığımız int,varchar,float,datetime gibi veri tiplerine ek olarak sınırlarımızı daha da genişleten yeni veri tipleri karşımıza çıkmaktadır.

            SQL Server 2008 ile gelen;bu yeni veri tiplerini aşağıdaki gibi bir gruplamaya sokabiliriz.(Bu makalemizde üçüncü grup olan Hiyerarşik Veri Tipleri üzerinde duracağız)

Ø 
Uzaysal Veri Tipleri: Bu veri tipleri GEOMETRY ve GEOGRAPHY
veri tiplerini içermektedir. Bu verilere de  Uzaysal Veriler denmektedir.

Ø  Yeni Date ve Time Veri Tipleri:
Bu veri tipleri,esnek Date ve Time verilerinin tutulmasını sağlamaktadır.Örneğin;1753 yılından önceki yılların yada 3.33 milisaniye den daha kısa zaman aralıklarının,veri tabanında saklanmasına imkan sağlıyorlar.

Ø  Hierarchyid Veri Tipleri :
Hiyerarşik verilerin tutulduğu tipler.Örneğin; çalışan => müdür ilişkisinin tutulmasına imkan sağlayan veri tipleridir.

Ø  FileStream Desteği : Büyük objelerin dosyalarda tutulması ve bu dosyaların database ile entegrasyonun sağlanması ise veri tiplerine getirilen bir başka kullanışlı yeniliktir.

Şimdi;yeni Hiyerarşik Veri Tiplerine ve sağladığı imkanlara bakalım.(Önceki bağlı makalelerimizde Uzaysal Veri Tiplerini ve Date-Time Veri Tiplerini incelemiştik)

3)SQL Server 2008’de Yeni Hiyerarşik Veri Tipleri :

Hiyerarşik verilere örnek olarak;organizasyon ve yönetim tabloları,ürün katalogları,dizin yapılarının tutulma şekilleri gösterilebilir.Hiyerarşik veriler birbiriyle ilişki halinde olan üyelerden oluşan bir yapıdır.Basitçe ifade etmek gerekirse parent-child ilişkisi bir hiyerarşik yapıdır.(üst-ast ilişkisi olarak düşünülebilirler.)Parent denilen kök üyenin;türeyen kolları (child),olabileceği gibi olmaya da bilir,aynı durum child için de geçerlidir.

SQL Serverda Hiyerarşik veriler 3 farklı yolla ele alınabilir.

Ø  XML yapıları kullanarak.Bu durum bütün uygulama ve kullanıcıların verilerinin XML ile ilişkilendirilmesini gerektirir.Fakat heterojen yapılar için XML veriler bazen aşırı zorlayıcı olabilirler.

Ø  Verileri ilişkisel tablolarda tutarak ve sonra bunları SELF JOINlerle birleştirerek.Bu da tabii ki karmaşık T-SQL sorguları gerektirmektedir.Ayrıca yönetim ve sürdürülebilme gibi konularda zorluklar ortaya çıkabilmektedir.

Ø  SQL Server 2008 ile gelen yeni hierarchyid veri tipini kullanmak.

Hierarchyid veri tipi ; hiyerarşik verilerimizi tanımlayabilmenin yanında,ilişkili veriler arasında yeni gelen fonksiyonlar aracılığıyla işlem yapabilme imkanını da tanımaktadır.

Hierarchyid veri tipi;DATE ve TIME veri tipleri gibi yerel bir tip değildir,sistem tanımlı UDT(User Definied Type) bir tiptir.Bu yeni tipimiz; Microsoft.SqlServer.Types.dll altında yer almaktadır.Uygulamalarda Microsoft.SqlServer.Types aduzayı aracılıgıyla kullanabilir.

Teknik olarak Hieararchyid veri tipleri CLR UDT’dir bu yüzden SQL Serverda CLR’yi aktif yapmanız gerektiğini düşünebilirsiniz ama Hieararchyid tipler sistem tanımlı tip olduğundan dolayı CLR aktif yapmanız gerekmemektedir.

Ş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