Makale Özeti

Bu makalede Stored Precedure ve Trigger'larda sıkça kullandığımız Cursor (İşaretçiler)'ların genel kullanım şeklini inceliyoruz.

Makale

Giriş

T-Sql İşaretçileri (cursors), çalışan bir T-Sql ifadesinin sonuçlarına diğer T-Sql kodlarının ve yapıların erişmesine olanak sağlayan bir yapıdır. Genellikle “stored precedure”ler, “trigger”lar ve geliştiriciler tarafından yazılan T-Sql komutkarı içerisinde kullanılmaktadırlar. Gelin şimdi T-Sql işaretçilerinin stored precedure veya trigger dahilindeki genel kullanım şeklini inceleyelim.

İşaretçilerin Çalışma Şekli:

İşaretçilerin kullanımında önce işaretçiden geriye döndürülecek veri ile ilgili değişkenler tanımlanır. Burada dikkat edilmesi gereken noktalar, işaretçiden döndürülecek verinin herbir sütunu için bir değişken tanımlanması, tanımlanan değişkenlerin ilişkilendirilmiş sütun verilerisini tutabilecek büyüklükte ve iligili sütun verisi ile uygun tipte tanımlanmasıdır.

Declare @Isaretci_Ad varchar(100)
Declare @Isaretci_Soyad varchar(120)

Değişkenlerin tanımlanmasından sonra Bir işaretçi tanımlaması yapılır. Tanımlanan bu işaretçi bir T-Sql sorgu cümlesi ile ilişkilendirilir. Ayrıca işaretçinin tanımlanması sırasında işaretçi ile ilgili isim, salt-okunur olup olmadığı gibi özellikler de belirtilir.

İşaretçi ile ilişkilendirilmiş sorgunun çalışarak işaretçinin açılması için “Open” komutu kullanılır. İşaretçi açıldığında sorgu sonucunda oluşan satırlar üzerinde dolaşmak için “Fetch ... Into” komutu kullanılır. “Fetch ... Into” komutu işaretçinin o an üzerinde olduğu sorgu sonucu satırının sütun bilgilerini, sütunlarla ilişkilendirilmiş değişkenlere yükler. Bu yolla, diğer T-Sql ifadeleri işaretçi ile çekilen bilgilere erişebilir. T-Sql işaretçileri, aynı anda birden fazla satırı gösteremezler; bir anda bir işaretçi yalnız bir satırı işaret edebilir. “Fetch” komutu sorgu sonucu üzerindeki navigasyonu da sağlar. Örneğin “Fetch Next ... Into” şeklinde kullanıldığında, işaretçinin o anda gösterdiği satırdan bir sonraki satıra işaretçiyi hareket ettirir ve o satırın bilgilerini değişkenlere atar.

İşaretçi ile yapılacak işlemler bitirildikten sonra işaretçinin kapatılması gerekmektedir. Bu işlem için “Close” komutu kullanılır. İşaretçiyi kapatmak işaretçinin bellekte tükettiği kaynağı küçültür; işaretçi ile ilişkilendirlmiş sorgunun sonuçlarını bellekten siler ve olası kilitleri kaldırır. Ancak işaretçi kapatılsa da, bir nesne olarak bellekte kalmaya devam eder; daha sonra tekrar açılarak bir daha tanımlanmadan kullanılabilir. Diğer yandan işaretçi nesnesinin varlığı işaretçi ile aynı isimde başka bir işaretçi tanımlanmasına engel olur. Bu bağlamda “Deallocate” komutu işaretçi ile ilgili tüm kaynakları boşaltır; işaretçi nesnesini de bellekten siler. Bu yolla başta kullanılan işaretçi ismi kullanılarak, yeni bir işaretçi tanımlanabilir.

İşaretçilerin Durumunun İzlenmesi

Mevcut veritabanı bağlantısı dahilinde tanımlanmış işaretçilerin listesi “sp_cursor_list” sistem “stored procedure”u ile alınabilir. Bunun yanından mevcut bağlantı dahilinde tanımlı bir işaretçi ile ilgili bilgiler de “sp_describe_cursor”, “sp_describe_cursor_columns” ve “sp_describe_cursor_tables” stored precedure’ları yardımı ile öğrenilebilmektedir..

Bir işaretçi ile ilişkilendirilmiş sorgu ifadesinin dödürdüğü kayıt sayısı “@@Cursor_Rows” sistem fonksiyonu ile öğrenilebilir. Bunun için bir başka yol “sp_cursor_list” veya “sp_describe_cursor” sistem metodlarının kullanılmasıdır. Bu metodların döndürdüğü kaydın “Cursor_rows” isimli sütununda ilgili işaretçi ile ilişkilendirilmiş kayıt sayısı tutulur. Tabii ki bu bilgilerin alınabilmesi için sözkonusu işaretçinin “Open” komutu ile açılmış olması gerekmektedir.

Açılmış bir işaretçi üzerinde çalıştırılan her “Fetch” komutu, veritabanı bağlantısı bazında global olan “@@Fetch_Status” isimli değişkeni güncelleyer. Bu değişken bir veritabanı bağlantısı dahilinde yapılan son “Fetch” işleminin başarılı olup olmadığını gösterir. Son “Fetch” işleminin durumu aynı zamanda “sp_describe_cursor” sistem metodunun dödürdüğü kaydın “fetch_status” sütunundan da öğrenilebilir. “@@Fetch_Status” değişkeni içerisinde tutulan değer, fetch işleminin ilk kayıt veya son kayıt için yapılıp yapılmadığını da ifade eder. @@Fetch_Status değişkeni veritabanı bağlantısı bazında global olduğundan, bir veritabanı bağlantısı dahilinde çalıştırılan her “Fetch” komutu bu değişkeni sıfırlar ve yeniden günceller. Bu nedenle, eğer son “Fetch” işleminin statüsü daha sonra size gerekecekse, bu değerin başka bir değişkende yedeklenmesinde fayda vardır. Sizin çalıştırdığınız “Fetch” komutunun ardından bir “Insert”, “Update” veya “Delete” ifadesi çalışıyor olsa da, yedekleme işlemini “Fetch” işleminin hemen ardından yapmanız gerekmektedir. Bunun nedeni çalıştıracağınız “Insert”, “Delete” veya “Update” komutu ile içerisinde işaretçi ile işlem yapılan bir trigger’ın tetiklenme ihtimalidir. “@@Fetch_Status” değişkenin bu karmaşık durumuna karşın “sp_describe_cursor” sistem metodu ile dönen kaydın “fetch_status” isimli sütınu sadece metoda parametre olarak verilen işaretçi için çalıştırılan son “Fetch” işleminin sonucunu döndürür. Bu değer aynı veritabanı bağlantısı dahilinde çalıştırılan diğer “Fetch” işlemlerinden etkilenmez. Tabii ki, aynı işaretçi için çalıştırılan “Fetch” işlemleri bu değeri de değiştirecektir.

Bir “Fetch” işlemi gerçekleştirildikten sonra, işaretçi “Fetch” komutu ile çekilen kadyın üzerinde konumlanır. “Fetch” komutu ile çekilen kayda, “Current Row” denir. Eğer işaretçinizi tanımlarken özel olarak “Read-Only (Salt-Okunur)” tanımlamadıysanız, “Fetch” işlemi ile çektiğiniz kayıt üzerinde “Update” veya “Delete” komutları çalıştırılabilir. Bu komutlar kullanılırken tanımlanacak koşul ifadesi “Where Current Of <İşaretçi Adı>” şeklinde olmalıdır.

Bir işaretçi tanımlaması (Declare komutu) sırasında işaretçiye verilen isim lokal veya global olabilir. Global işaretçi isimlerine işaretçi tanımlamasının yapıldığı veritabanı bağlantısı dahilinde çalışan herhangi bir T-Sql ifadesinden, “stored precedure”den, “triger”dan referans edilebilir. Lokal işaretçi isimleri ise işaretçinin içerisinde tanımlanmış olduğu T-Sql ifadesi, “stored procedure” veya “trigger” dışından referans edilemezler. Bu sayede bir stored procedure veya trigger dahilinde tanımlı lokal işaretçilere dışarıdan izinsiz bir şekilde erişim engellenmiş olur.

İşaretçi Değişkenin Kullanılması

Mirosoft SQL Server için “cursor (işaretçi)” aynı zamanda bir veri tipidir. Bir işaretçi bir işaretçi değişkeni ile iki şekilde ilişkilendirilebilir:

Birinci Kullanım:
DECLARE @BenimIsaretciDegiskenim CURSOR
DECLARE BenimIsaretcim CURSOR FOR
SELECT LastName FROM Northwind.dbo.Employees
SET @MyIsaretciDegiskenim = BenimIsaretcim

İkinci Kullanım:
DECLARE @BenimIsaretciDegiskenim CURSOR
SET @BenimIsaretciDegiskenim = CURSOR SCROLL KEYSET FOR
SELECT LastName FROM Northwind.dbo.Employees

Bir işaretçi, işaretçi tipindeki bir değişken ile ilişkilendirildikten sonra, T-Sql ifadelerinde işaretçinin ismi yerine işaretçi değişkeni kullanılabilir. “Stored procedure”ların geri dönüş değerleri “cursor” veritipinde tanımlanabilir. Bu sayede “stored procedure”lerin lokal işaretçileri dışarısı ile paylaşabilmeleri sağlanmaktadır.

T-Sql İşaretçilerinin Kullanılması

T-Sql işaretçi isimleri ve değişkenleri sadece T-Sql ifadeleri içerisinden referans edilebilir; Oledb, Odbc, Ado ve DbLibrary içerisinden kullanılamazlar. Örneğin, Declare Cursor ile bir işaretçi yaratıp, onu “Open” komutu ile açtığınızda, bu işaretçi üzerinde Odbc SqlFetch komutunu çalıştırmanız mümkün değildir. İşaretçi işlemeye ihtiyaç duyulan uygulamalarda T-Sql işaretçileri yerine, uygulamanın kullanabileceği uygulama kütüphaneleri içerisinde bulunan işaretçi bileşenlerinin kullanılması gerekmektedir. Yukarıdaki duruma karşın, uygulamalarda T-Sql kullanarak “Fetch” komutu çalıştırıp, dönüş değerleri uygulama içerisindeki değişkenlere atanabilir. T-Sql’deki “Fetch” komutu birden fazla kaydı geri döndüremediğinden, uygulama içesinde bu komutu kullanmak çok anlamlı olmayabilir. Çünkü, uygulamadan gönderilen her “Fetch” komutu, uygulama sunucusu ile veritabanı sunucusu arasında birdizi işleme neden olacaktır. Bu nedenle, uygulama içerisinden T-Sql “Fetch” komutu kullanmak yerine uygulamanın geliştirildiği ortamda kullanılan veritabanı işleme kütüphanelerindeki benzer fonksiyonları barındıran bileşenleri kullanmak daha makuldür. T-SQL işaretçileri stored procedure ve trigger’lar içerisinde kullanıldıklarında oldukça efektiflerdir. “Stored Procedure” ve “trigger”lar veritabanı içerisinde yapılandırılmış olarak durduğundan, “Fetch” işlemlerinde hızlı çalışır ve ağ üzerinde minimum trafik oluştururlar.