【问题标题】:Declare Variable for a Query String为查询字符串声明变量
【发布时间】:2011-04-19 12:01:43
【问题描述】:

我想知道在 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

这样可以吗?

【问题讨论】:

标签: sql sql-server sql-server-2005 tsql dynamic-sql


【解决方案1】:

可以,但需要使用动态 SQL。
我建议在继续之前阅读The curse and blessings of dynamic SQL...

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)

Dynamic SQL 只是一个 SQL 语句,在执行之前被组合成一个字符串。因此发生了通常的字符串连接。每当您想以不允许的 SQL 语法执行某些操作时,都需要动态 SQL,例如:

  • 单个参数,用于表示 IN 子句的逗号分隔值列表
  • 一个表示值和 SQL 语法的变量(IE:您提供的示例)

EXEC sp_executesql 允许您使用绑定/preparedstatement 参数,因此您不必担心转义单引号/等以进行 SQL 注入攻击。

【讨论】:

  • 我认为这是最正确的答案。我最近也一直在使用 SQL Server 2005,并且不可能像 OP 想要的那样使用变量来替换查询字符串(会产生语法错误)。正如@Ponies 所说,变量不能同时包含语法和数据类型。动态 SQL 是通过字符串在 SQL Server 中构建查询的方法。请记住要小心您的报价和类型!您执行的字符串需要转换或强制转换某些类型,例如 datetime 或 int 以进行字符串连接。
【解决方案2】:
DECLARE @theDate DATETIME
SET @theDate = '2010-01-01'

然后更改您的查询以使用此逻辑:

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

【讨论】:

  • 等一下。如果问题清楚地显示了两个不同的日期,那不能是答案。你最后是如何编码的 @StealthRT ?答案中的“2010-08-31”日期在哪里?此外,该问题清楚地询问您是否可以使用 DECLARE 变量将代码替换为另一个 SELECT 语句。正确答案如下。
【解决方案3】:

使用执行

您可以使用以下示例来构建 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)

使用 sp_executesql

通过使用这种方法,您可以确保传递到查询中的数据值是正确的数据类型,并避免使用更多的引号。

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

Reference

【讨论】:

    【解决方案4】:

    我会指出,在评分最高的答案The Curse and Blessings of Dynamic SQL 中链接的文章中,作者声明答案是不使用动态 SQL。几乎滚动到最后才能看到这个。

    摘自文章:“正确的方法是将列表解压成带有用户定义函数或存储过程的表。”

    当然,一旦列表在表中,您就可以使用连接。我无法直接对评分最高的答案发表评论,所以我只是添加了这条评论。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-12
    • 2021-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多