Declarar variable para una cadena de consulta

92

Me preguntaba si había una forma de hacer esto en MS SQL Server 2005:

  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

¿Es posible hacerlo?

StealthRT
fuente

Respuestas:

96

Es posible, pero requiere el uso de SQL dinámico.
Recomiendo leer La maldición y las bendiciones del SQL dinámico antes de continuar ...

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)

El SQL dinámico es solo una declaración de SQL, compuesta como una cadena antes de ejecutarse. Entonces ocurre la concatenación de cadenas habitual. Se requiere SQL dinámico siempre que desee hacer algo en la sintaxis SQL que no está permitido, como:

  • un solo parámetro para representar una lista de valores separados por comas para una cláusula IN
  • una variable para representar tanto el valor como la sintaxis SQL (IE: el ejemplo que proporcionó)

EXEC sp_executesql le permite usar parámetros de vinculación / declaración preparada para que no tenga que preocuparse por escapar de comillas simples / etc. para ataques de inyección SQL.

Ponis dios mio
fuente
Creo que esta es la respuesta más correcta. También he estado usando SQL Server 2005 recientemente, y no es posible usar una variable para el reemplazo de la cadena de consulta como el OP quiere (genera errores de sintaxis). Las variables no pueden incluir tanto sintaxis como tipos de datos, como dice @Ponies. El SQL dinámico es el camino a seguir para crear consultas en SQL Server a través de cadenas. ¡Solo recuerde tener cuidado con sus citas y tipos! La cadena que ejecuta requiere que algunos tipos, como datetime o int, se conviertan o se conviertan para la concatenación de cadenas.
RoboBear
52
DECLARE @theDate DATETIME
SET @theDate = '2010-01-01'

Luego cambie su consulta para usar esta lógica:

AND 
(
    tblWO.OrderDate > DATEADD(MILLISECOND, -1, @theDate) 
    AND tblWO.OrderDate < DATEADD(DAY, 1, @theDate)
)
cazador
fuente
2
Aférrate. Esa no puede ser la respuesta si la pregunta muestra claramente dos fechas diferentes. ¿Cómo lo codificó al final @StealthRT? ¿Dónde está la fecha '2010-08-31' en la respuesta? Además, la pregunta pregunta claramente si puede usar las variables DECLARE para sustituir el código en otra instrucción SELECT. La respuesta adecuada está a continuación.
Fandango68
2

Usando EXEC

Puede utilizar el siguiente ejemplo para crear una declaración SQL.

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)

Usando sp_executesql

Con este enfoque, puede asegurarse de que los valores de datos que se pasan a la consulta sean los tipos de datos correctos y evitar el uso de más comillas.

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

Referencia

Somnath Muluk
fuente
1

Señalaré que en el artículo vinculado en la respuesta mejor calificada The Curse and Blessings of Dynamic SQL, el autor afirma que la respuesta es no usar SQL dinámico. Desplácese casi hasta el final para ver esto.

Del artículo: "El método correcto es descomprimir la lista en una tabla con una función definida por el usuario o un procedimiento almacenado".

Por supuesto, una vez que la lista está en una tabla, puede usar una combinación. No pude comentar directamente sobre la respuesta mejor calificada, así que acabo de agregar este comentario.

DavidG
fuente
Esto no proporciona una respuesta a la pregunta. Una vez que tenga suficiente reputación , podrá comentar en cualquier publicación ; en su lugar, proporcione respuestas que no requieran aclaración por parte del autor de la pregunta . - De la crítica
Sam M
Gracias Sam. Actualizaré mi comentario con detalles una vez que implemente lo que sugiere Erland Sommarskog. También haré referencia a él por su nombre, ya que merece crédito por la respuesta.
DavidG