2013-10-04 46 views
3

如果沒有參數傳遞給存儲過程,則應返回所有結果。存儲過程中的動態sql無法獲取所需結果

如果我通過任何一個參數值,然後應顯示爲每個參數

alter proc SearchEmployee --'','','','' 
    @Name varchar(50)=null, 
    @Age int=null, 
    @Gender varchar(50)=null, 
    @Email varchar(50)=null 
as 
begin 

    declare @sql varchar(max), @sqlwhere varchar(max) 
    set @sqlwhere = ''; 

    set @sql = 'select * from employee' 

    if ((@Name is not null) and @Name <> '') 
    begin 
     set @sqlwhere=' Name='+ @Name 
    end 
    else if ((@Age is not null) and @Age <> '') 
    begin 
     set @sqlwhere='and Age='+ cast(@Age as varchar(50)) 
    end 
    else if ((@Email is not null) and @Email <> '') 
    begin 
     set @sqlwhere=' and email='+ @Email 
    end 
    else if ((@Gender is not null) and @Gender <> '') 
    begin 
     set @sqlwhere=' and Gender='+ @Gender 
    end 

    if (@sqlwhere <> '') 
    begin 
     set @sql = @sql + ' where ' + @sqlwhere; 
    end 
    else 
    begin 
     set @sql = @sql; 
    end 

    print @sql 
    exec (@sql) 
end 

employee

Name Age Gender email 
anurag 24 Male [email protected] 
abhi 22 Male [email protected] 
ruchi 23 Female [email protected] 
siba 24 Male [email protected] 
mukua 24 Male [email protected] 
prachi 24 Female [email protected] 
preeti 24 Female [email protected] 

執行

SearchEmployee '','','','' 

給了我所有的結果。

但執行列出了錯誤

SearchEmployee 'anurag','','',''` 

select * from employee where Name=anurag 

錯誤:

Msg 207, Level 16, State 1, Line 1
Invalid column name 'anurag'.

請幫我修改查詢。我在哪裏做錯了?

+1

這個'select * from employee where Name = anurag'試圖找到行'名稱'列匹配'anurag'列的值 - 但有**沒有** 'anurag'專欄!你需要把你的字符串值放入**單引號!** - 'select * from employee where Name ='anurag'' –

回答

2

你忘了單引號包裹的varchar/nvarchar的值的任何參數。
此外,如果您不提供@Name,則您的動態查詢將包含例如where and Age = ...部分,即在第一過濾條件之前將具有不想要的and
甚至更​​多,在您的實現中,由於鏈條可能只有一個過濾器條件(零個或一個)。但似乎你想使用所有傳遞(即非空)參數。

順便說一句,沒有必要使用動態查詢。例如,您可以使用此查詢:

select 
    * 
from employee 
where 
    Name = isnull(@Name, Name) 
    and Age = isnull(@Age, Age) 
    and email = isnull(@Email, email) 
    and Gender = isnull(@Gender, Gender) 

select 
    * 
from employee 
where 
    (@Name is null or Name = @Name) 
    and (@Age is null or Age = @Age) 
    and (@Email is null or email = @Email) 
    and (@Gender is null or Gender = @Gender) 

UPD。在評論中回答問題。是的,它可以完成。並再次ISNULL(或聚結)功能:

-- remove set @sqlwhere = '' in top of the query so @sqlwhere 
-- will be null - it's usefull. 
-- also change if (@sqlwhere <> '') to if (@sqlwhere is not null) 

set @sqlwhere = isnull(@sqlwhere + ' and ', '') 
       + ' Age = ''' + cast(@Age as varchar(50)) + ''' '; 

-- as you see, I also added single quotes wrapping for @Age value 

isnull具有簡單的邏輯 - 如果第一個參數is not null然後返回它,否則返回第二個參數。在sql中還有一個規則,如果null值出現在算術運算或字符串連接(我們的情況)中,那麼所有結果將是null。所以如果@sqlwhere is null那麼@sqlwhere + ' and '也將是null。這意味着如果@sqlwhere沒有條件,那麼在and這個詞中就沒有必要。
希望這是明確的:)

+0

非常棒的解釋..我嘗試了兩種。而且兩者工作正常。 – anurag

+0

但正如你所說「另外,如果你不提供@Name,你的動態查詢將有例如where和age = ...部分,即在第一個過濾條件之前會有不需要的。 。所以可以在動態查詢中處理?有沒有什麼辦法可以在動態查詢中做到這一點? – anurag

+0

@anurag看看答案更新部分 – pkuderov

1

調試此類動態SQL的最佳方式是簡單地刪除exec (@sql)並僅打印SQL語句。然後,您可以使用該語句來處理查詢,直到其正確,然後根據您所做的更改在代碼中進行調整。

在這種情況下,你會發現你缺少參數周圍的撇號。嘗試是這樣的:

set @sqlwhere=' Name='+ '''' + @Name + '''' 

做那是傳遞文本

+0

Yaa它的工作。但我在這裏有一個問題。爲什麼需要4個引號。我有點困惑在這裏..請解釋我..它會對我有幫助... – anurag

+0

它是像''''+ @Name +''''。第一個報價是第一個字符串的開始。然後接下來的兩個引號是單引號。然後關閉字符串。所以這使得'''。然後+ @名稱+。然後第二個字符串開始然後接下來的兩個引號做一個單引號。然後最後一個報價是第二個字符串的結尾。我的理解是否正確? – anurag

+0

基本上,爲了得到一個'在動態sql中顯示,你必須顯示爲''''。其原因是,一個單獨的'永遠不會顯示,因爲它指的是字符串的開始和結束。通過使用4 ..前2說它的一個字符串和中間2互相抵消,併成爲一個'。我知道它令人困惑。我總是把它當作1使用4撇號來學習。 – logixologist