存储过程中的动态sql无法获取所需的结果

时间:2013-10-04 17:53:32

标签: sql sql-server-2008

如果没有参数传递给存储过程,它应该返回所有结果。

如果我传递任何一个参数,那么值应按参数

显示
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    anu@gmail.com
abhi    22  Male    abhi@gmail.com
ruchi   23  Female  ruchi@gmail.com
siba    24  Male    siba@gmail.com
mukua   24  Male    mukua@gmail.com
prachi  24  Female  prachi@gmail.com
preeti  24  Female  preeti@gmail.com

执行

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

给了我所有的结果。

但执行以下操作会出错

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

select * from employee where  Name=anurag

错误:

  

Msg 207,Level 16,State 1,Line 1
  列名称'anurag'无效。

请帮我修改查询。我在哪里做错了?

2 个答案:

答案 0 :(得分:2)

您忘了用单引号包装varchar / nvarchar值 此外,如果您不提供@Name,您的动态查询将包含where and Age = ...部分,即在首次过滤条件之前会有不需要的and 更重要的是,在您的实现中,由于if else if链,只能有一个过滤条件(零或一)。但似乎你想要使用所有传递(即非空)参数。

顺便说一句,没有必要使用动态查询。例如,您可以使用此查询:

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(或coalesce)函数:

-- 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字就没有必要了 希望很清楚:)

答案 1 :(得分:1)

调试此类动态SQL的最佳方法是简单地删除exec (@sql)并只打印SQL语句。然后,您可以使用该语句处理查询,直到其右侧,然后根据您所做的更改在代码中进行调整。

在这种情况下,您会发现参数周围缺少撇号。尝试这样的事情:

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

对于传入文本的任何参数

执行此操作