Makale Özeti

Yığın içersinde dinamik bir sql sorgusu oluşturup, bu sorgu sonucunu bir değişkene aktararak kullanabilmek incelenmiştir.

Makale

Kimi zaman sorgumuzdaki alan isimlerinin, veritabanının veya tablo isimlerinin parametrik olmasını, dolayısıyla dinamik bir sorgu oluşturmak isteriz. Peki bu sorgu sonucundan bir değeri okuyup -örneğin bir değişkene atayarak- nasıl kullanabilirizin cevabını irdeliyorum bu yazıda..

Exec() yapısı ile dinamik bir sorgu hazırlayabiliriz. Şöyle ki,

use master
go

declare @sVch_Database varchar(50)
declare @sVch_Schema varchar(50)
declare @sVch_Table varchar(50)

set @sVch_Database = 'MyDatabase'
set @sVch_Schema = 'MySchema'
set @sVch_Table = 'MyTable'

exec
(
    'select rows' +
    ' from ' + @sVch_Database + '.dbo.sysindexes' +
    ' where id = object_id(''' + @sVch_Database + '.' + @sVch_Schema + '.' + @sVch_Table + ''')' +
    ' and indid < 2'
)

Şeklindeki kullanım ile, “MyDatabase” veritabanından, “MySchema” dahilindeki “MyTable” tablosunun kayıt sayısını sorgulattık.

Kayıt sayısı için count() fonksiyonunu kullanabiliriz. Fakat bu fonksiyon kayıt sayısını kullanıldığı anda hesaplayarak döndürür. Büyük datalar için performans kaybı söz konusudur. Buradaki sorgumuzda ise, her tablonun kayıt sayısının zaten saklı tutulduğu alana erişiyoruz. Ayrıca bir işlem gerçekleştirmiyoruz.

Kayıt sayısını görmek istiyorsak sorun yok. Fakat örneğin bir saklı yordam ( stored procedure ) içersinde bu değeri bir değişkene atma ihtiyacımız var ise, sorun yaşarız. Çünkü exec() yapısı içersindeki sorgu ayrı bir yığın ( session ) olarak değerlendirilir. Haliyle saklı yordamımızın içersindeki değişkeni tanımaz. Veya dinamik sorgumuzun içersinde tanımladığımız değişkene, bu sorguyu çağırdığımız yığından ulaşamayız.

Bu sorunu aşmak için sp_executesql saklı yordamı ile dinamik bir sorgu hazırlamamız gerekmektedir. Çünkü sp_executesql parametrik çalışır ve bu parametreleri, sorgumuza gönderip-geri alabiliriz.

Aynı örnek üzerinden incelersek;

use master
go

declare @sVch_Database varchar(50)
declare @sVch_Schema varchar(50)
declare @sVch_Table varchar(50)

set @sVch_Database = 'MyDatabase'
set @sVch_Schema = 'MySchema'
set @sVch_Table = 'MyTable'

declare @sInt_RowCount int
declare @sNVch_Sql nvarchar(max)

set @sNVch_Sql =
    'select @sInt_RowCount = rows' +
    ' from ' + @sVch_Database + '.dbo.sysindexes' +
    ' where id = object_id(''' + @sVch_Database + '.' + @sVch_Schema + '.' + @sVch_Table + ''')' +
    ' and indid < 2'

exec sp_executesql @sNVch_Sql, N'@sInt_RowCount int output', @sInt_RowCount output

select @sInt_RowCount

Burada önemi bir nokta bulunmaktadır. sp_executesql ‘in aldığı ilk parametrenin ( sorgumuzun bulunduğu cümleciğin ) NVarChar türünde olması gerekmektedir. Aksi durumda derleme anında şu şekilde bir hata ile karşılaşırız;

Procedure expects parameter '@statement' of type 'ntext/nchar/nvarchar'.

Yine aynı şekilde yazdığımız ikinci parametrenin de NVarChar olması gerekmektedir. Bu parametre, oluşturduğumuz sorgu içerindeki parametreleri tanımlamamıza yarar. Haliyle sorgumuzun da NVarChar olduğunu düşünüldüğünde yadırganmaması gerekir.

Ayrıca gönderdiğimiz parametrenin işlevini belirtmemiz gerekmektedir. Çıktı olarak değerlendirecek isek output sözcüğünü eklemeliyiz.

Son olarak da tanımladığımız parametreleri sp_executesql ‘e sırasıyla ( birden fazla ise ) gönderiyoruz.

:: Almış olduğum birkaç not..

sp_executesql ‘in parametrik yapısı sayesinde, Sql enjeksiyon ( sql injection ) riski problem teşkil etmez. Fakat kullandığımız yapıda veritabanı, tablo ve alan isimleri gibi değerlerin parametrik olması adına sorgu cümleciğini string ifadeleri birleştirerek oluşturmamız, Sql enjeksiyona maruz kalabilmemize yol açmaktadır. Dikkatli olunması gerekir. Eğer amaç sadece sorgudaki parametrelere değer gönderip, değişkenlere ulaşmak ise, tüm bu parametreleri sp_executesql ‘e tanımlayıp göndermemiz en güvenli metoddur.

Dinamik bir sorgu hazırladığımızda ( exec() veya sp_executesql farketmez ), sorgu çalıştırılasaya kadar derlenmez ( compiling ). Haliyle ifadenin geçerliliği denetlenmediği için ( parsing ) sentaks ( syntax ) hataları sorgu işletilmeden bilinemez.

NVarChar ‘ın limiti 4000 karakterdir. Bu sebeple sorgumuz 4000 karakteri geçmemelidir.

:: Kaynak(lar)

http://msdn.microsoft.com/en-us/library/ms188332(SQL.90).aspx
http://msdn.microsoft.com/en-us/library/ms188001(SQL.90).aspx