2011-08-27 53 views
1

我有一個SQL Server中的動態SQL查詢。所以我構建它,將其設置爲變量,然後嘗試根據日期格式化where子句。但是,當我嘗試這樣做時,我得到「多部分標識符」FIELD NAME「不能被綁定。我相信這是因爲實際的表格從克勞斯處於動態的狀態,所以在編譯之前無法看到它們。任何方式在這個?如何在動態SQL查詢中引用字段?

在這裏,我試圖說,給我指定的地方年+月之間DOB所有的人,例如,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) 
+1

這看起來並不需要是動態SQL。爲什麼你不能使用[這種技術](http://stackoverflow.com/questions/7212339/how-do-i-do-a-comparison-with-just-a-month-and-year-not-a -complete-date/7214021#7214021)從你以前的問題? –

+0

請在提問時指出SQL Server的版本。 @ Martin的記憶顯然比我的記憶好,但是我們並不都知道你上次被問及「SQL Server的哪個版本?」 –

回答

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

我知道你已經固定您的問題,並接受一個答案,但我想我還要指出還有其他一些潛在的改進(對您和未來的讀者來說都是如此)。

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?

更妙的是隻存儲他們的出生日期是擺在首位的日期。爲什麼要將年份和月份存儲爲單獨的字符串?你一定有這樣的理由,但我無法想象它是什麼。它所做的只是使這種字符串匹配效率低於實際使用日期的效率,降低了對值執行任何類型的日期操作的能力,並且使得驗證傳入的值非常困難。現在,您的東西會後嗆比它應該有,如果有人調用以下:

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

,他們可以這樣做,因爲你任何執行任何驗證。對於DATE變量,至少返回的錯誤消息是有意義的。現在使用我們的任一版本,他們只會得到一個空的結果集。