【问题标题】:Multi Columns filtration in stored procedure in SQL ServerSQL Server 存储过程中的多列过滤
【发布时间】:2015-06-17 14:16:58
【问题描述】:

我的 Windows 窗体应用程序中有更多控件(假设有 10 个带有文本框、下拉菜单、单选按钮的控件)用于过滤并非强制的数据,因此用户可以使用 1 个或更多控件过滤数据。

现在我必须创建一个存储过程,用于根据输入过滤数据。

例如:如果用户在 1 个文本框控件中输入了一些文本,而剩下的 9 个控件的数据为空,我必须仅根据用户输入的那个文本框来过滤数据。

如果用户在 1 个文本框控件和 1 个下拉列表中输入了一些文本,而剩下的 8 个控件的数据为空,我必须仅根据用户输入的那个文本框和下拉列表来过滤数据。

我该怎么办?

在源代码中:

如果用户在任何控件上输入/选择文本,我将值作为参数传递,否则我将作为“null”传递给其余所有其他参数。

在存储过程中:

我给出了所有 10 个控件参数以从源代码中获取值,基于我正在过滤数据的参数。

if @Param1=null && @Param2=null && @Param3='SomeText'
    begin
        sELECT * FROM tABLE1 wHERE TableCOLUMN3=@Param3
    END
 if @Param1=null && @Param2='SomeText' && @Param3='SomeText'
    begin
        sELECT * FROM tABLE1 wHERE TableCOLUMN2=@Param2 AND TableCOLUMN3=@Param3
    END

注意:我需要将每个表列的数据过滤到每个参数,简单假设@Param1--TableCOLUMN1,@param2--TableCOLUMN2,过滤器取决于参数文本。

如果我这样做,我的存储过程会更大,因为我有 10 个参数要检查(仅供参考,我在示例上方给出了 3 个参数)。

我想要的是:

由于我给出了 10 个参数,因此基于具有值的参数(除 NULL 之外的一些文本),我只需要使用 where 条件过滤数据。

有没有其他方法可以做到这一点,或者有人有其他方法可以做到这一点吗?

【问题讨论】:

标签: sql sql-server sql-server-2008


【解决方案1】:

只要你让你的参数默认为 null 并且要么不为你不需要的参数传递值或传递 dbnull 值,那么你就可以像这样过滤

CREATE PROC dbo.SAMPLE
(
    @Param1 VARCHAR(255) = NULL,
    @Param2 VARCHAR(255) = NULL,
    @Param3 VARCHAR(255) = NULL,
    @Param4 VARCHAR(255) = NULL,
    @Param5 VARCHAR(255) = NULL,
    @Param6 VARCHAR(255) = NULL
)
AS
BEGIN
    SELECT  * 
    FROM    Table1
    WHERE   (@Param1 IS NULL OR TableCOLUMN1 = @Param1)
            AND (@Param2 IS NULL OR TableCOLUMN2 = @Param2)
            AND (@Param3 IS NULL OR TableCOLUMN3 = @Param3)
            AND (@Param4 IS NULL OR TableCOLUMN4 = @Param4)
            AND (@Param5 IS NULL OR TableCOLUMN5 = @Param5)
    OPTION (RECOMPILE) -- as JamesZ suggested to prevent caching
END


EXEC dbo.SAMPLE @Param2 = 'SomeText'  -- only filter where TableCOLUMN2 = @Param2

【讨论】:

  • 很有用,因为你可以做(@Param1 = '' OR TableCOLUMN1 in (@Param1ToList))之类的事情
【解决方案2】:

我会建议这样的事情:

SELECT * 
FROM TABLE1 
WHERE TableCOLUMN1=ISNULL(@Param1,TableCOLUMN1)
AND TableCOLUMN2=ISNULL(@Param2,TableCOLUMN2)
AND TableCOLUMN3=ISNULL(@Param3,TableCOLUMN3)
AND TableCOLUMN4=ISNULL(@Param4,TableCOLUMN4)
... and so on...

如果您指定 param1,这将根据值过滤 column1,否则它将使用始终为 true 的 columnvalue 本身。 但这只有在您不使用 @Param 值在每种情况下都为 NULL 时才有效。

【讨论】:

    【解决方案3】:

    如果表很大/你需要使用索引来获取行,这种逻辑的问题是,索引不能真正使用。基本上有两种方法可以做到这一点:

    1. option (recompile) 添加到@Ionic 或@user1221684 的选择语句的末尾。这将导致语句每次执行时都重新编译,如果经常调用它可能会占用大量 CPU。

    2. 创建动态 SQL 并使用 sp_executesql 调用它

    例子:

    set @sql = 'SELECT * FROM TABLE1 WHERE '
    
    if (@Param1 is not NULL) set @sql = @sql + 'TableCOLUMN1=@Param1 AND '
    if (@Param2 is not NULL) set @sql = @sql + 'TableCOLUMN2=@Param2 AND '
    if (@Param3 is not NULL) set @sql = @sql + 'TableCOLUMN3=@Param3 AND '
    
    -- Note: You're not concatenating the value of the parameter, just it's name
    
    set @sql = @sql + ' 1=1' -- This handles the last 'and'
    
    EXEC sp_executesql @sql,
         N'@Param1 varchar(10), @Param2 varchar(10), @Param3 varchar(10)',
         @Param1, @Param2, @Param3
    

    作为一个额外的选项,您可以在您的原始想法和完全动态的想法之间进行某种混合,以便它至少处理最常见的搜索条件,以便可以有效地获取。

    【讨论】:

    • 在语句末尾添加 1=1 有什么好处,而不是在开头并仅使用 ' AND TableCOLUMN1=@Param1 '
    • 没关系。这就是我这样做的方式,出于某种原因......:D
    • 在一张大桌子上,CPU 开销不会太大——通常情况下。在大表上重新编译时,您将获得更多性能,然后如果您的计划不好,您将失去优势。 :-)
    【解决方案4】:

    通常每个参数都有一个默认值,例如 int 的默认值为零。所以使用这个你可以有条件。请参阅下面的考试 sql。

    create procedure [dbo].[sp_report_test](
    @pParam1 int,
    @pParam2 int ,
    @pParam3 int,
    @pParam4 varchar(50)
    )
    AS
    
    SELECT 
      *
    FROM [vw_report]
    where   
    (@pParam1 <= 0 or Column1 = @pParam1) and
    (@pParam2 <= 0 or Column2 = @pParam2) and
    (@pParam3 <= 0 or Column3 = @pParam3) and
    (@pParam4 is null or len(@pParam4) <= 0 or Column4 = @pParam4);
    
    GO
    

    【讨论】:

      猜你喜欢
      • 2018-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-19
      • 1970-01-01
      相关资源
      最近更新 更多