如何在动态SQL查询中引用字段?

时间:2011-08-27 19:31:16

标签: sql sql-server sql-server-2008 stored-procedures

我在SQL Server中有一个动态的SQL查询。所以我构建它,将其设置为varible,然后我尝试根据日期格式化where子句。但是,当我尝试这样做时,我得到“多部分标识符'FIELD NAME'不能被绑定。我相信这是因为实际的表格在claus中是动态的,所以在编译之前它们是不可见的。有什么方法吗?

在这里,我试图说,给我所有在指定年份+月份之间的人员,例如,201001和201012将是2010年的全年。这是部分代码....

    ALTER PROCEDURE get_persons_by_search_criteria

@month_from as nvarchar(2) = null,
@year_from as nvarchar(4) = null,
@month_to as nvarchar(2) = null,
@year_to as nvarchar(4) = null


AS

declare @from_date varchar(10)
declare @to_date varchar(10)
declare @sqlstr varchar(5000)

set @sqlstr = ' SELECT     
    Person.PersonID, 
    Person.FirstName, 
    Person.LastName, 
FROM    Person '

--Attemtping to create a value like 201108 (year + month)
set @from_date = Convert(VarChar(10), @year_from) + Replace(Str(@month_from, 2), ' ', '0')  
set @to_date = Convert(VarChar(10), @year_to) + Replace(Str(@month_to, 2), ' ', '0') 

set @sqlstr = @sqlstr +  ' WHERE '
set @sqlstr = @sqlstr + Convert(VarChar(10), Person.DOBYear) + Replace(Str(Person.DOBMonth, 2), ' ', '0') 
set @sqlstr = @sqlstr + ' BETWEEN '   + @from_date + ' and ' + @to_date


exec(@sqlstr)

2 个答案:

答案 0 :(得分:2)

此行给出错误,因为在构建动态字符串时PERSON表未打开。

set @sqlstr = @sqlstr + Convert(VarChar(10), Person.DOBYear) + Replace(Str(Person.DOBMonth, 2), ' ', '0')

试试这个

set @sqlstr = @sqlstr + ' Convert(VarChar(10), Person.DOBYear) + Replace(Str(Person.DOBMonth, 2), '' '', ''0'') '

应该为你做诀窍..

答案 1 :(得分:1)

我意识到你已经修复了你的问题并接受了答案,但我想我还会指出其他一些潜在的改进(无论是你还是未来的任何读者)。

ALTER PROCEDURE dbo.get_persons_by_search_criteria
    @month_from VARCHAR(2) = NULL,
    @year_from  VARCHAR(4) = NULL,
    @month_to   VARCHAR(2) = NULL,
    @year_to    VARCHAR(4) = NULL
AS
BEGIN 
   SET NOCOUNT ON;

   SELECT
       PersonID, DOBYear, DOBMonth
   FROM
       dbo.Person
   WHERE 
       DOBYear + RIGHT('0' + DOBMonth, 2) + '01'
       BETWEEN @year_from + RIGHT('0' + @month_from, 2) + '01'
           AND @year_to   + RIGHT('0' + @month_to,   2) + '01'
   ORDER BY 
       PersonID, DOBYear, DOBMonth;
END
GO

眼睛不容易,更容易遵循,更容易维护吗?

要点:

  • always use the schema prefix在创建,更改或引用对象时。

  • 当您不需要支持Unicode数据时,不要使用Unicode(NCHAR / NVARCHAR)(例如,数字永远不需要包含变音符号)。 Choosing the right data type在这个特定情况下可能不那么重要,但在其他情况下它可能至关重要。

  • 将您的程序正文包裹在BEGIN / END中 - 这可以防止您在不知不觉中从查询窗口中拾取其他不需要的代码。并始终在程序开始时使用SET NOCOUNT ON。我在“stored procedure best practices checklist。”

  • 中解决了这些问题和其他问题
  • 为避免行为更改,您应始终包含ORDER BY子句。如果今天它按名字命令,明天开始按姓氏排序,有人会抱怨。请参阅this post的第二部分。

  • 尽可能学习在没有动态SQL的情况下编写SQL。如果您要继续使用动态SQL,请至少尝试使用sp_executesql而不是EXEC()。我在最近的另一个问题中解释了原因:SQL Server use EXEC/sp_executesql or just plain sql in stored procedure?

更好的方法是首先将他们的出生日期存储为DATE。为什么要将年份和月份存储为单独的字符串?你必须有这样的理由,但我无法想象它是什么。所有这一切都使得这种字符串匹配效率低于实际使用日期时的效率,降低了对值执行任何类型的日期操作的能力,并且使得验证传入的值非常困难。现在你的东西如果有人打电话给以下人员,它会比以前更加窒息:

EXEC get_persons_by_search_criteria 
    @month_from = '97',
    @year_from  = 'Audi',
    @month_to   = 'TT',
    @year_to    = 'Oy!!';

他们可以做什么,因为你不进行任何验证。对于DATE变量,至少返回的错误消息是有意义的。现在,对于我们的任何一个版本,他们只会得到一个空的结果集。