SQL 更改 where 子句中的过滤器数量

Posted

技术标签:

【中文标题】SQL 更改 where 子句中的过滤器数量【英文标题】:SQL alter number of filters in where clause 【发布时间】:2013-11-22 15:37:14 【问题描述】:

有时我需要更改 WHERE 子句中的过滤器数量,我正在寻找最好的建议。 这是一个场景:

表 1(Col1、Col2、Col3) Col1 包含唯一 ID。 Col2 包含数字 0 到 1000,非唯一。 Col3 包含字母 A 到 Z,不唯一。

我有一个 StoredProc1,它只接受一个参数,但根据参数的值,它应该只搜索 Col2 或同时搜索 Col2 和 Col3。查看 1 或 2 列的决定是任意的,存储过程需要针对性能进行优化。

下面的代码可以完成这项工作,但非常难以管理。我有一个包含 128 个不同分支的存储过程,如果我再添加一个条件,它将构成另外 128 个分支和总共 6000 行代码。一定有更好的办法。

我正在考虑声明另一个变量并将其设置为始终不匹配的默认值。然后根据 StoredProc1 参数中传递的值,将第二个变量设置为相关值。这个解决方案的问题是它会降低第二个过滤器不适用的搜索性能。 我无法更改 StoredProc1 定义,因为它被无数其他进程调用。 到目前为止,我唯一想到的是创建另一个 SP 并在条件为真时从主 SP 调用它,并将当前 proc 保留为 else 分支。

StoredProc1 ( @filter ) as
begin
    if (@filter = 1)
    begin
        select col1, col2, col3
        from Table1
        where Col2 = @filter or Col2 = 'A'
    end
    else
    begin
        select Col1, Col2, Col3
        from Table1
        where Col2 = @Filter
    end
end

【问题讨论】:

动态 SQL 是你的朋友 请提供输入参数的完整列表。例如 Col1FilterPresent, Col1FilterPresent, ... Col1FulterValue ... 。我认为有一种方法(虽然不确定),但我需要输入参数。您还需要过滤器作为 AND 或 OR? Erland Sommarskog 的Dynamic Search Conditions in T-SQL @filter 是整数还是 varchar? 【参考方案1】:
StoredProc1 ( @filter ) as
begin
  select col1, col2, col3
  from Table1
  where Col2 = @filter or (@filter = '1' and Col2 = 'A')
end

无论您选择哪种解决方案,您都会失去性能。每次都可能需要编译动态 SQL。您的“分支”方法工作正常。

【讨论】:

【参考方案2】:
StoredProc1
@filter DataType
as
begin
  DECLARE @Sql NVARCHAR(MAX);

SET @Sql = N'select Col1, Col2, Col3 
           from Table1 WHERE 1 = 1 '
          + CASE WHEN   @filter = 1 THEN N' AND Col2 = @Param or Col2 = ''A''' 
            ELSE N' AND Col2 = @Filter' END

EXECUTE sp_executesql @Sql 
                     , N'DECLARE @Param DataType'
                     , @Param = @filter
end

您可以有多个 Case 语句来检查多个参数并构建您的 sql 字符串。 执行此类操作的方式更加灵活和安全。

【讨论】:

这正是我想要的。我不知道你是否可以在 WHERE 子句中插入 CASE。您是否期望此选项会带来较高的性能损失? @user2611947 - CASE 语句不是结果 sql 语句中 Where 子句的一部分,而只是在字符串连接中为这个变量构建值。构建 sql 语句字符串将是您最不担心的性能问题。 @user2611947 您可能想对执行计划和 sp_executesql 的缓存进行一些研究。它有时。如果每次都必须编译查询,那么您将失去将其设为 proc 的理由。【参考方案3】:

在某些情况下,你可以有类似的东西:

declare @iFilterCol1 int;
declare @iFilterCol2 int;
declare @iFilterCol3 varchar(100);

set @iFilterCol1 = 5;
set @iFilterCol2 = 100;
set @iFilterCol3 = 'aaa';

select col1, col2, col3
from Table1
where 
    (Col1 = case when @iFilterCol1 is not null then @iFilterCol1 else Col1 end) 
    and (Col2 = case when @iFilterCol2 is not null then @iFilterCol2 else Col2 end) 
    and (Col3 = case when @iFilterCol3 is not null then @iFilterCol3 else Col3 end);

在这种情况下,当您将值分配给 @iFilterCol1 时,您将按 Col1 进行过滤,否则您将跳过它。与其他 2 列相同。考虑到我使用AND。 Yuo 可以改用OR,但两者的组合取决于您要应用的过滤器,在某些情况下是不可能的。

【讨论】:

以上是关于SQL 更改 where 子句中的过滤器数量的主要内容,如果未能解决你的问题,请参考以下文章

SQL WHERE 子句类似于 JOIN 查询

访问 SQL 子查询 WHERE 子句不过滤结果 [关闭]

SQL 过滤在 where 子句中使用 case

使用 WHERE 子句中的过滤器优化 OUTER JOIN 查询。(查询规划器)

SQL Server - 按可变数量的参数过滤查询

如何在 JSON 上应用复杂的数据过滤器,例如 SQL where 子句