开发者

How do I reference a field in a dynamic sql query?

I have a dynamic sql query in SQL Server. So I build it, set it to a varible and then I attempt to format a where clause based on a date. However, when I attempt to do this, I get "The multi-part identifier 'FIELD NAME" can not be bound. I beleive this is because the actual tables are in a dynamic from claus so they can't be seen until it is compiled. Any way around this?

Here I am attempting to say, give me all Persons where DOB between YEAR+MONTH specified, for example, 201001 and 201012 would be the entire year of 2010. Here is the code in part....

    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)开发者_如何学JAVA, @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)


This line gives the error, because the PERSON table is not open when you build the dynamic string.

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

Try this

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

Should do the trick for you..


I realize you've already fixed your issue and accepted an answer, but I thought I would also point out a few other potential improvements (both for you and for any future readers of the question).

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

Isn't that easier on the eyes, easier to follow, and easier to maintain?

Summary:

  • always use the schema prefix when creating, altering or referencing objects.

  • don't use Unicode (NCHAR/NVARCHAR) when you don't need to support Unicode data (numbers will never need to contain umlauts, for example). Choosing the right data type might not be that important in this specific case, but it can be crucial in others.

  • wrap your procedure body in BEGIN/END - this will prevent you from unknowingly picking up other unwanted code from the query window. And always use SET NOCOUNT ON at the beginning of your procedures. I address these and other issues in my "stored procedure best practices checklist."

  • to avoid changes in behavior, you should always include an ORDER BY clause. If today it orders by first name, and tomorrow it starts ordering by last name, someone is going to complain. See the second section of this post.

  • learn to write SQL without dynamic SQL, when possible. If you're going to continue using dynamic SQL, at least please try to use sp_executesql instead of EXEC(). I explained the reasons in another recent question: SQL Server use EXEC/sp_executesql or just plain sql in stored procedure?

Even better would be to just store their date of birth as a DATE in the first place. Why would you store the year and month as separate strings? There must be some reason you are doing this but I can't imagine what it is. All it does is make this kind of string matching less efficient than if you were actually using dates, reduces your ability to perform any type of date operations on the values, and makes it very difficult to validate the values passed in. Right now your stuff is going to choke later than it should have to if someone calls the following:

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

Which they could do, because you perform no validation whatsoever. With DATE variables at least the error message that comes back would make sense. Right now with either of our versions they'll just get an empty result set.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜