Dinamik Sql Sorgusundan Sonuç Değerini Okumak

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,

DynamicSqlQuery-01

Resme tıklayarak sorgunun metin haline ulaşabilirsiniz.

Ş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;

DynamicSqlQuery-02

Resme tıklayarak sorgunun metin haline ulaşabilirsiniz.

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. Haliyle ifadenin geçerliliği denetlenmediği için yazım 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

  • Evrim OĞUZ

    Merhaba Dinamik SQL sorgusu ile ilgili bir sorum olacaktı. sp_executesql() ile kullandığım bir dinamik sql sorgusu kullanıyorum. Örnek olarak;

    declare @sql nvarchar(max)
    SET @Sql = concat(‘insert into ewrim.deneme (ad)’
    ,’VALUES (‘ , char(39),@son_agirlik ,char(39),’)’)
    EXECUTE sp_executesql @Sql
    Veri tabanına kayıt yaparken Türkçe karakter problemi yaşıyorum.
    ancak dinamik sorgu kullanmazsam bu sorunu yaşamıyorum. Yani;
    insert into ewrim.deneme(ad) values(@son_agirlik) şeklinde kullanırsam karakter problemi olmuyor. Fakat bu sadece sorunu anlamak için yazdığım bir kod. Orjinal kodda dinamik kullanmak zorundayım.
    Bu sorunun çözümü ile ilgili bir bilginiz var mı?

    • http://www.brkshn.com/ Burak

      Merhaba,

      Aslında Türkçe karakter problemi collation ile alakalı. Öncelikle tablonun bulunduğu veritabanının varsayılan collation’ına bakın. Atıyorum bu Turkish_CI_AS veya TR’ye özgü benzer birşey olmayabilir (örn: SQL_Latin1_General_CP1_CI_AS olabilir) Bu tür durumlarda varchar(40) yerine nvarchar(40) kullanmak gerekmektedir.

      Veritabanı collation’unu değiştirmemize izin verilmiyor olabilir. Ve ilgili alanları nvarchar yapmak istemiyor olabilirsiniz. O vakit tablonuz üzerinde varchar gibi alanların collation’unu belirlemeniz gerekmekte.

      Özetle yanlış anlamadı isem, collation meselesini biraz araştırıp üzerinde çalışırsanız sorunu çözebilirsiniz.

      Veritabanı varsayılan collation’ı SQL_Latin1_General_CP1_CI_AS olan bir sistemde şu örneği denedim. TestTable1 adında bir tablo oluşturdum ve ad adında varchar(40) bir alan ekledim. Aşağıdaki kodu çalıştırdığımda TR karakter sorunu vardı. Sonrasında tablodaki alanı ve aşağıdaki değişkeni nvarchar(40) yaptım. Sorun çözüldü.

      declare @ad varchar(40)
      set @ad = ‘Şey, Ağaç var mı orda?’

      declare @sql nvarchar(max)
      set @Sql = concat(
      ‘insert into TestTable1 (ad)’,
      ‘ values(@ad)’)

      exec sp_executesql @Sql, N’@ad varchar(40)’, @ad

      Son olarak farklı bir konu ise ve ben boşa yazdıysam kusura bakmayın :). Yazdıklarınızdan derdinizi bu şekilde anladım. Tekrar yazın elimden geldiğince yardımcı olurum. Görüşmek üzere.. :)