【问题标题】:Parametrize the WHERE clause?参数化 WHERE 子句?
【发布时间】:2010-06-10 13:28:16
【问题描述】:

我需要为 SQL Server 2008 编写一个存储过程来执行大型 select 查询,并且我需要它来过滤结果,并通过过程的参数指定过滤类型。我找到了一些这样的解决方案:

create table Foo(
   id bigint, code char, name nvarchar(max))
go

insert into Foo values
 (1,'a','aaa'),
 (2,'b','bbb'),
 (3,'c','ccc')
go

create procedure Bar
       @FilterType  nvarchar(max),
       @FilterValue nvarchar(max) as
begin
    select * from Foo as f
    where case @FilterType
          when 'by_id'   then f.id
          when 'by_code' then f.code
          when 'by_name' then f.name end
          = 
          case @FilterType
          when 'by_id'   then cast(@FilterValue as bigint)
          when 'by_code' then cast(@FilterValue as char)
          when 'by_name' then @FilterValue end
end
go

exec Bar 'by_id', '1';
exec Bar 'by_code', 'b';
exec Bar 'by_name', 'ccc';

我发现这种方法行不通。可以将所有列强制转换为nvarchar(max) 并将它们作为字符串进行比较,但我认为这会导致性能下降。

是否可以在存储过程中参数化where 子句而不使用EXEC sp_executesql 之类的构造?

【问题讨论】:

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


    【解决方案1】:

    对于大型过滤器要求,这可能会变得有点冗长,但我认为它可能更高效/更易于阅读/维护:

    create procedure Bar
           @Id int,
           @Code nvarchar,
           @name nvarchar
    begin
        select * from Foo as f
        where (@id = -1 or f.ID = @id)
        and (@Code = '' or f.Code = @Code)
        and (@Name = '' or f.Name = @Name)
    end
    go
    
    exec Bar 1, '', ''
    exec Bar -1, 'code', ''
    exec Bar -1, '', 'name'
    

    这还允许您同时过滤多个项目。

    【讨论】:

    • 我认为您可以用 ors 替换外部的“and”,并删除 or 子句的第一部分,如下所示: ...其中 f.ID = @id 或 f.Code = @Code 或 f.Name = @Name。 (这适用于空值,除非您正在搜索设置为空的列。)
    • @Philip Kelley - 取决于您希望过滤器执行的操作 - 如果您想返回与传递的任何字段匹配的位置,那就可以了。
    【解决方案2】:

    试试这个

    create procedure Bar 
           @FilterType  nvarchar(max), 
           @FilterValue nvarchar(max) as 
    begin 
        select * from Foo as f 
        where 
            (@FilterType ='by_id'   and f.id =cast(@FilterValue as bigint) )
            OR
            (@FilterType ='by_code'   and f.code =cast(@FilterValue as char) 
            OR
            (@FilterType ='by_name'   and f.name =@FilterValue
    
    end 
    go 
    

    【讨论】:

    • 谢谢你,但它不起作用... SQL Server 尝试执行所有and 分支并且无法转换右侧的数据...
    • 你确定吗? OR 部分会处理它
    【解决方案3】:
    declare @field varchar(20)
    
    declare @value varchar(100)
    
    set @field = 'customerid'
    set @value = 'ALFKI'
    
    set @field = 'Country'
    set @value = 'Germany'
    
    set @field = 'ContactTitle'
    set @value = 'Owner'
    
    select * from customers
    where (customerid = (case when @field = 'customerid' then  @value else customerid end)
    and ContactTitle = (case when @field = 'ContactTitle' then  @value else ContactTitle end)
    and country = (case when @field = 'Country' then  @value else country end))
    

    示例适用于 Northwind 数据库。
    希望这会有所帮助。

    编辑:注释上面的 @field@value 的 3 个值中的任何 2 个。

    【讨论】:

      【解决方案4】:

      如果您没有很多过滤条件,您可以考虑创建委托函数并将请求分派给适当的函数。例如,

      create procedure Bar
             @FilterType  nvarchar(max),
             @FilterValue nvarchar(max) as
      begin
          case @FilterType
                when 'by_id'   then FilterById(@FilterValue)
                when 'by_code' then FilterByCode(@FilterValue)
                when 'by_name' then FilterByName(@FilterValue)
                end
      end
      go
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-26
        • 2016-03-30
        • 1970-01-01
        相关资源
        最近更新 更多