Bir Sorgu Dizesi için Değişken Bildirme


92

MS SQL Server 2005'te bunu yapmanın bir yolu olup olmadığını merak ediyordum:

  DECLARE @theDate varchar(60)
  SET @theDate = '''2010-01-01'' AND ''2010-08-31 23:59:59'''

  SELECT    AdministratorCode, 
            SUM(Total) as theTotal, 
            SUM(WOD.Quantity) as theQty, 
            AVG(Total) as avgTotal, 
            (SELECT SUM(tblWOD.Amount)
                FROM tblWOD
                JOIN tblWO on tblWOD.OrderID = tblWO.ID
                WHERE tblWO.Approved = '1' 
                AND tblWO.AdministratorCode = tblWO.AdministratorCode
                AND tblWO.OrderDate BETWEEN @theDate
            )
 ... etc

Bunu yapmak mümkün mü?


Yanıtlar:


97

Mümkün, ancak dinamik SQL kullanmayı gerektirir. Devam etmeden önce Dinamik SQL'in laneti ve kutsamalarını
okumanızı tavsiye ederim ...

DECLARE @theDate varchar(60)
SET @theDate = '''2010-01-01'' AND ''2010-08-31 23:59:59'''

DECLARE @SQL VARCHAR(MAX)  
SET @SQL = 'SELECT AdministratorCode, 
                   SUM(Total) as theTotal, 
                   SUM(WOD.Quantity) as theQty, 
                   AVG(Total) as avgTotal, 
                  (SELECT SUM(tblWOD.Amount)
                     FROM tblWOD
                     JOIN tblWO on tblWOD.OrderID = tblWO.ID
                    WHERE tblWO.Approved = ''1''
                      AND tblWO.AdministratorCode = tblWO.AdministratorCode
                      AND tblWO.OrderDate BETWEEN '+ @theDate +')'

EXEC(@SQL)

Dinamik SQL, çalıştırılmadan önce bir dizge olarak oluşturulmuş bir SQL ifadesidir. Böylece olağan dize birleştirme gerçekleşir. SQL sözdiziminde izin verilmeyen bir şey yapmak istediğinizde dinamik SQL gereklidir, örneğin:

  • IN yan tümcesi için virgülle ayrılmış değerler listesini temsil eden tek bir parametre
  • hem değeri hem de SQL sözdizimini temsil eden bir değişken (IE: sağladığınız örnek)

EXEC sp_executesql bind / readystatement parametrelerini kullanmanıza izin verir, böylece SQL enjeksiyon saldırıları için tek tırnak / etc kaçışıyla uğraşmanıza gerek kalmaz.


Bunun en doğru cevap olduğunu düşünüyorum. Son zamanlarda SQL Server 2005'i de kullanıyorum ve OP'nin istediği gibi sorgu dizisi değişimi için bir değişken kullanmak mümkün değil (sözdizimi hataları üretir). @Ponies'in dediği gibi, değişkenler hem sözdizimi hem de veri türlerini içeremez. Dinamik SQL, dizeler aracılığıyla SQL Server'da sorgu oluşturmanın yoludur. Alıntılarınız ve türleriniz konusunda dikkatli olmayı unutmayın! Yürüttüğünüz dize, datetime veya int gibi bazı türlerin dönüştürülmesini veya dize birleştirme için dönüştürülmesini gerektirir.
RoboBear

52
DECLARE @theDate DATETIME
SET @theDate = '2010-01-01'

Ardından, bu mantığı kullanmak için sorgunuzu değiştirin:

AND 
(
    tblWO.OrderDate > DATEADD(MILLISECOND, -1, @theDate) 
    AND tblWO.OrderDate < DATEADD(DAY, 1, @theDate)
)

2
Dayan. Soru açıkça iki farklı tarih gösteriyorsa, cevap bu olamaz. @StealthRT sonunda bunu nasıl kodladınız? Cevapta '2010-08-31' tarihi nerede? Ayrıca soru, kodu başka bir SELECT deyimiyle değiştirmek için DECLARE değişkenlerini kullanıp kullanamayacağınızı açıkça sorar. Doğru cevap aşağıdadır.
Fandango68

2

EXEC kullanma

SQL deyimi oluşturmak için aşağıdaki örneği kullanabilirsiniz.

DECLARE @sqlCommand varchar(1000)
DECLARE @columnList varchar(75)
DECLARE @city varchar(75)
SET @columnList = 'CustomerID, ContactName, City'
SET @city = '''London'''
SET @sqlCommand = 'SELECT ' + @columnList + ' FROM customers WHERE City = ' + @city
EXEC (@sqlCommand)

Sp_executesql kullanma

Bu yaklaşımı kullanarak, sorguya aktarılan veri değerlerinin doğru veri türleri olmasını sağlayabilir ve daha fazla teklifin kullanılmasını önleyebilirsiniz.

DECLARE @sqlCommand nvarchar(1000)
DECLARE @columnList varchar(75)
DECLARE @city varchar(75)
SET @columnList = 'CustomerID, ContactName, City'
SET @city = 'London'
SET @sqlCommand = 'SELECT ' + @columnList + ' FROM customers WHERE City = @city'
EXECUTE sp_executesql @sqlCommand, N'@city nvarchar(75)', @city = @city

Referans


1

En çok oy alan cevapta bağlantılı olan makalede , Dinamik SQL'in Laneti ve Kutsaması yazarın cevabın dinamik SQL kullanmak olmadığını belirttiğini belirteceğim. Bunu görmek için neredeyse sonuna kadar kaydırın.

Makaleden: "Doğru yöntem, listeyi kullanıcı tanımlı bir işleve veya saklı yordama sahip bir tablo halinde açmaktır."

Elbette, liste bir tabloya girdikten sonra bir birleştirme kullanabilirsiniz. En çok oy alan cevaba doğrudan yorum yapamadım, bu yüzden bu yorumu ekledim.


Bu soruya bir cevap vermiyor. Yeterli itibara sahip olduğunuzda , herhangi bir gönderi hakkında yorum yapabileceksiniz ; bunun yerine soruyu soranın açıklamasını gerektirmeyen yanıtlar verin . - Yorumdan
Sam M

Teşekkürler Sam. Erland Sommarskog'un önerdiği şeyi uyguladığımda yorumumu ayrıntılarla güncelleyeceğim. Cevap için övgüyü hak ettiği için ona adıyla da atıfta bulunacağım.
DavidG
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.