T-SQL'de neden yapabileceğimi düşündüğüm gibi değişkenleri neden kullanamıyorum?


18

Affet beni, SQL dünyasına geçen bir geliştiriciyim. Değişkenler ekleyerek bazı SQL geliştirebileceğini düşündüm ama beklediğim gibi çalışmadı. Birisi bana bunun neden işe yaramadığını söyleyebilir mi? Etrafında bir çalışma istemiyorum, bunun neden işe yaramadığını bilmek istiyorum, bunun iyi bir neden olduğundan emin olduğum gibi hayal etmeliyim, ama şu anda bana atlamıyor.

DECLARE @DatabaseName varchar(150)
SET @DatabaseName = 'MyAmazingDatabaseName'

CREATE DATABASE @DatabaseName
GO

USE @DatabaseName
GO

Bunun için dinamik sql kullanmanız gerekir. mssqltips.com/sqlservertip/1160/…
Stijn Wynants

3
Yorum yaptığınız için teşekkürler, ama soruma göre, aradığım cevap bu değil. Gösterdiğim gibi neden yapamayacağımı bilen biri olup olmadığını bilmek istiyorum.
gareth

2
Çünkü USEkomutu bir parametre ile kullanmak mümkün değildir .
TT.

2
Halihazırda verilen, fakat kendi cevabı için yeterli olmayan cevaplara ek olarak, değişkenler mevcut partinin maksimumuna kadar kapsamlandırılır. (Değişkenleri SQL Server'da olduğundan daha dar kapsamayı mümkün olup olmadığını elden bilmiyorum.) Böylece sahip olduğunuz an GO, daha önce bildirilen değişken kaybolur. Senaryonuz için geçerli olabilecek veya olmayabilecek SQLCMD değişkenlerine bakmak isteyebilirsiniz.
CVn

1
Veritabanı adlarını ve sütun adlarını dize değerleri olarak düşünme eğilimindeyiz, ancak SQL bağlamında bunlar Tanımlayıcılardır. Yapmaya çalıştığınız şey x = 7'yi beklemekle aynı olurdu; 'x' = 7 ile aynı olmak; başka bir dilde. Nasıl x = 7 ile aynı 'x' = 7 ile ilgilenen bir bilgisayar dili oluşturulabiliyorsa, Tablo X Yarat 'Tablo X Yarat' ile aynı davranan bir RDBMS oluşturulabilir. Ama bu SQL olmazdı.
user1008646

Yanıtlar:


20

Değişkenler için Kitaplar çevrimiçi sayfasına

Değişkenler, nesne adları veya anahtar kelimeler yerine yalnızca ifadelerde kullanılabilir. Dinamik SQL ifadeleri oluşturmak için EXECUTE kullanın.

Örneğin, değişkeninizi bir where yan tümcesinde kullandıysanız, beklediğiniz şekilde çalışır. Neden gelince, ben ayrıştırıcı değişkeni değerlendirmek ve böylece varlığını kontrol etmek için bir şey olduğunu düşünüyorum. Yürütme sırasında, sorgu ilk olarak sözdizimi ve nesneler için ayrıştırılır ve ardından, ayrıştırma başarılı olursa, sorgu değişkenin hangi noktada ayarlanacağını yürütür.

DECLARE @name varchar(20);
SET @name = 'test';

CREATE TABLE [#tmp]([val] varchar(10));

insert into #tmp
values('test')

SELECT *
FROM [#tmp]
WHERE [val] = @name;

3
Dinamik SQL'den mümkün olduğunca kaçınılması gerektiğini unutmayın. evalJavaScript ve Python gibi prosedür dillerindeki işlevleri kullanmak için SQL analogudur . Güvenlik açıkları oluşturmanın hızlı bir yoludur.
jpmc26

1
@ jpmc26: Dinamik SQL içermeyen bunu yapmanın daha güvenli yolu nedir?
Robert Harvey

1
@RobertHarvey Sadece en iyi şekilde kaçınılması, her zaman tam olarak aynı işlevselliğe sahip bir alternatif olduğu anlamına gelmez. ;) Çoğu zaman, cevabın bir kısmı, "Soruna tamamen farklı bir çözüm kullanın." Bazen yapılması en iyi şeydir, ancak iyi bir miktar kasıtlı olmadan ve alternatifleri ihmal etmediğinizden emin olmadan değil ve o zaman bile sağlıklı bir dikkatle gelmelidir.
jpmc26

2
@ jpmc26: OP örneği, "Önce Kod" ORM'in veritabanındaki tabloları ayarlamak için yapabileceklerine benziyor. Dinamik SQL prensipte güvensiz olsa da, son kullanıcı asla bu koda dokunmaz.
Robert Harvey

@RobertHarvey "Son kullanıcı" olarak gördüğünüz kişilere bağlıdır. Bir DB dağıtan bir komut dosyası için, geliştiriciyi ve bazı sys yöneticilerini "son kullanıcı" olarak kabul ediyorum. Bu durumda, kazaları önlemek için başka bir sebep yoksa, güvensiz girişi reddetmek için sisteme tasarım yapardım. Ayrıca, "asla dokunma"
gelince

17

SQL deyimlerinde değişkenlerin kullanımıyla ilgili sınırlamalar SQL mimarisinden kaynaklanır.

Bir SQL ifadesinin işlenmesinde üç aşama vardır:

  1. Hazırlık - İfade ayrıştırılır ve hangi veritabanı nesnelerine erişildiğini, bunlara nasıl erişildiğini ve nasıl ilişkili olduklarını belirten bir yürütme planı derlenir. Yürütme planı, plan önbelleğine kaydedilir .
  2. Bağlama - ifadedeki değişkenler gerçek değerlerle değiştirilir.
  3. Yürütme - önbelleğe alınan plan ilişkili değerlerle yürütülür.

SQL Server, hazırlık adımını programcıdan gizler ve Oracle ve DB2 gibi daha geleneksel veritabanlarından çok daha hızlı yürütür. Performans nedenlerinden ötürü, SQL en uygun yürütme planını belirlemek için çok fazla zaman harcar, ancak yalnızca bir yeniden başlatmadan sonra ifadeyle ilk kez karşılaşıldığında bunu yapar.

Bu nedenle, statik SQL'de , değişkenler yalnızca yürütme planını geçersiz kılmayacakları yerlerde kullanılabilir, bu nedenle tablo adları, sütun adları (WHERE koşullarındaki sütun adları dahil) vb.

Dinamik SQL , kısıtlamalar etrafında çalışamayan durumlar için vardır ve programcı yürütmenin biraz daha uzun süreceğini bilir. Dinamik SQL kötü amaçlı kod enjeksiyonuna karşı savunmasız olabilir, bu yüzden dikkatli olun!


7

Gördüğünüz gibi, "neden" sorusu, tarihsel mantık ve dilin altında yatan varsayımlar da dahil olmak üzere farklı bir cevap gerektirir, bu adaleti gerçekten yapabileceğimden emin değilim.

SQL MVP Erland Sommarskog'un bu kapsamlı makalesi, mekaniğin yanı sıra bir gerekçe sağlamaya çalışıyor:

Dinamik SQL'in Laneti ve Bereketleri :

Önbellek Sorgu Planları

SQL Server'da çalıştırdığınız her sorgu bir sorgu planı gerektirir. Bir sorguyu ilk kez çalıştırdığınızda, SQL Server bunun için bir sorgu planı oluşturur - veya terminoloji giderken - sorguyu derler. SQL Server planı önbelleğe kaydeder ve sorguyu bir sonraki çalıştırışınızda plan yeniden kullanılır.

Bu (ve güvenlik, aşağıya bakınız) muhtemelen en büyük nedendir.

SQL, sorguların tek seferlik işlemler olmadığı, ancak tekrar tekrar kullanılacağı öncülünde çalışır. Tablo (veya veritabanı!) Sorguda gerçekten belirtilmezse, ileride kullanmak üzere bir yürütme planı oluşturmanın ve kaydetmenin bir yolu yoktur.

Evet, çalıştırdığımız her sorgu yeniden kullanılmayacak, ancak bu SQL'in varsayılan çalışma önceliğidir , bu nedenle "istisnalar" istisnadır.

Erland'ın birkaç başka nedeni listeledi ( saklı yordamları kullanmanın avantajlarını açıkça listelediğini unutmayın , ancak bunların çoğu ayrıca parametrelenmiş (dinamik olmayan) sorguların avantajlarıdır):

  • İzin Sistemi : SQL motoru, çalışacağınız tabloyu (veya veritabanını) bilmiyorsa bir sorguyu çalıştırma haklarına sahip olup olmadığınızı tahmin edemez. Dinamik SQL kullanarak "izin zincirleri" popo bir acıdır.
  • Ağ Trafiğini Azaltma : Depolanan proc ve birkaç parametre değerinin ağ üzerinden iletilmesi, uzun bir sorgu ifadesinden daha kısadır.
  • Kapsülleme Mantığı : Diğer programlama ortamlarından kapsülleme mantığının avantajlarına aşina olmalısınız.
  • Ne Kullanıldığını Takip Etme : Bir sütun tanımını değiştirmem gerekirse, onu çağıran tüm kodu nasıl bulabilirim? Bir SQL veritabanı içindeki bağımlılıkları bulmak için sistem prosedürleri vardır, ancak yalnızca kod saklı yordamlardaysa.
  • SQL Kodu Yazma Kolaylığı : Saklı bir yordamı oluşturduğunuzda veya değiştirdiğinizde sözdizimi denetimi gerçekleşir, bu nedenle umarım daha az hata oluşur.
  • Hataları ve Sorunları Ele Alma : Bir DBA, ayrı ayrı saklanan yordamların performansını sürekli değişen dinamik SQL'den çok daha kolay izleyebilir ve ölçebilir.

Yine, bunların her birinin buraya girmeyeceğim yüz nüansları var.


2

Dinamik sql kullanmanız gerekiyor

DECLARE @DatabaseName varchar(150) = 'dbamaint'
declare @sqltext nvarchar(max) = N''

set @sqltext = N'CREATE DATABASE '+quotename(@DatabaseName)+ ';'

print @sqltext 

-- once you are happy .. uncomment below
--exec sp_executesql @sqltext
set @sqltext = ''
set @sqltext = N'use '+quotename(@DatabaseName)+ ';'
print @sqltext 
-- once you are happy .. uncomment below
--exec sp_executesql @sqltext

aşağıda baskı çıktı .. bir kez sen uncomment exec sp_executesql @sqltextaçıklamaları gerçekten yürütülür ...

CREATE DATABASE [dbamaint];
use [dbamaint];

1
Evet teşekkürler, bunu biliyorum, ama neden değişkeni kullanamayacağınızı bilen var mı bilmek istiyorum?
gareth

T-SQL ayrıştırıcısı sözdizimi hataları atar. Ayrıştırıcının tanıdığı geçerli bir T-SQL değil.
Kin Shah

Teşekkürler Kin, eminim bunun için iyi sebepler olmalı. Belki veritabanı adları '@' ve muhtemelen daha karmaşık nedenler içerebilir.
gareth

1
Evet, @ içerebilirler ve bunun ana nedeni olduğunu düşünüyorum. msdn.microsoft.com/en-us/library/ms175874.aspx
Paweł Tajs

1
@gazeranco İnanın, SQL Server ile çalışan herkes şüphesiz daha fazla komutun sabit tanımlayıcılar yerine değişkenleri kabul etmesini ister.
db2
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.