Tsql 搜索查询动态与静态-SQL Server 2012

Tsql 搜索查询动态与静态-SQL Server 2012,tsql,sql-server-2012,sql-injection,dynamic-sql,Tsql,Sql Server 2012,Sql Injection,Dynamic Sql,我需要编写一个搜索查询(存储过程),其中输入参数的数量将超过15个。用户可以传递单个参数值或参数组合 最好的方法是什么 静态方法如下: DECLARE @FirstName VARCHAR(50) = 'XYZ' , @LastName VARCHAR(50) = 'ABC' , @MiddleName VARCHAR(50) = '999-9999%''; Select 1 as Abc where 1 like ''%1' SELECT * FROM [Person].[Person]

我需要编写一个搜索查询(存储过程),其中输入参数的数量将超过15个。用户可以传递单个参数值或参数组合

最好的方法是什么

  • 静态方法如下:

    DECLARE @FirstName VARCHAR(50) = 'XYZ' ,
    @LastName VARCHAR(50) = 'ABC' ,
    @MiddleName VARCHAR(50) = '999-9999%'';  Select 1 as Abc where 1 like ''%1'
    SELECT *
    FROM   [Person].[Person]
    WHERE  FirstName LIKE '%' + @FirstName + '%'
        OR LastName LIKE '%' + @LastName + '%'
        OR MiddleName LIKE '%' + @MiddleName + '%'
    
    DECLARE @FirstName VARCHAR(50) = 'XYZ', @LastName VARCHAR(50) = 'ABC', @MiddleName VARCHAR(50) = '999-9999%'
    
    DECLARE @select VARCHAR(5000) = 'Select * from [Person].[Person] '
    DECLARE @WhereClause VARCHAR(5000) = 'Where'
    IF (@FirstName IS NOT NULL OR @FirstName <> '')
        SET @WhereClause = @WhereClause + ' FirstName Like ''%' + @FirstName + '%'''
    
    IF (@LastName IS NOT NULL OR @LastName<> '') 
        IF (@WhereClause <> 'Where')
            SET @WhereClause = @WhereClause + ' OR LastName Like ''%' + @LastName+ '%'''
        ELSE
            SET @WhereClause = @WhereClause + ' LastName Like ''%' + @LastName+ '%'''
    
    IF (@MiddleName IS NOT NULL OR @MiddleName <> '') 
        IF (@WhereClause <> 'Where')
            SET @WhereClause = @WhereClause + ' OR MiddleName Like ''%' + @MiddleName + '%'''
        ELSE
            SET @WhereClause = @WhereClause + ' MiddleNameLike ''%' + @MiddleName + '%'''
    
  • 动态SQL方法如下所示:

    DECLARE @FirstName VARCHAR(50) = 'XYZ' ,
    @LastName VARCHAR(50) = 'ABC' ,
    @MiddleName VARCHAR(50) = '999-9999%'';  Select 1 as Abc where 1 like ''%1'
    SELECT *
    FROM   [Person].[Person]
    WHERE  FirstName LIKE '%' + @FirstName + '%'
        OR LastName LIKE '%' + @LastName + '%'
        OR MiddleName LIKE '%' + @MiddleName + '%'
    
    DECLARE @FirstName VARCHAR(50) = 'XYZ', @LastName VARCHAR(50) = 'ABC', @MiddleName VARCHAR(50) = '999-9999%'
    
    DECLARE @select VARCHAR(5000) = 'Select * from [Person].[Person] '
    DECLARE @WhereClause VARCHAR(5000) = 'Where'
    IF (@FirstName IS NOT NULL OR @FirstName <> '')
        SET @WhereClause = @WhereClause + ' FirstName Like ''%' + @FirstName + '%'''
    
    IF (@LastName IS NOT NULL OR @LastName<> '') 
        IF (@WhereClause <> 'Where')
            SET @WhereClause = @WhereClause + ' OR LastName Like ''%' + @LastName+ '%'''
        ELSE
            SET @WhereClause = @WhereClause + ' LastName Like ''%' + @LastName+ '%'''
    
    IF (@MiddleName IS NOT NULL OR @MiddleName <> '') 
        IF (@WhereClause <> 'Where')
            SET @WhereClause = @WhereClause + ' OR MiddleName Like ''%' + @MiddleName + '%'''
        ELSE
            SET @WhereClause = @WhereClause + ' MiddleNameLike ''%' + @MiddleName + '%'''
    
    将执行的结果SQL查询将是

    Select * from [Person].[Person] Where FirstName Like '%XYZ%' OR LastName Like '%ABC%' OR MiddleName Like '%999-9999%';  Select 1 as Abc where 1 like '%1%'
    
    这不好

    那么,以最佳性能编写代码的最佳方法是什么呢。

    我更喜欢方法#1。

    • 更容易维护#1中的代码
    • 在大多数情况下,1将比2快
    • 处理引号内部引号是一件令人头痛的事<代码>'或类似于'%'+@LastName'的LastName+ “%”
    • 动态sql更难调试。在这种情况下可能不是这样
    • 当您的需求发生变化时,您的动态代码将变得更加混乱和复杂 梅西耶
    • 查询计划不会缓存在#2中
    • SQL注入如您所示

      • 动态SQL通常会受到性能影响,因为它无法在SQL server中缓存查询计划

        我个人也喜欢方法1,但如果做得不好,那么它可能会非常慢,特别是因为像变量“%text%”这样的开放式语句可能需要大量时间来执行

        我的建议是让输入参数的默认值为null,然后按如下方式构造WHERE子句

        SELECT *
        FROM table t
        WHERE t.column1 = ISNULL(@param1, t.column1)
        AND t.column2 = ISNULL(@param2, t.column2)
        
        这意味着在未提供参数的实例中,它只返回所有其他匹配结果


        对于日期范围匹配,您可能需要做一些聪明的事情,但是,如果参数为NULL,则使用最小和最大可能的日期/时间,以确保所有记录都应在该范围内。

        如果
        t.column1
        为NULL,请避免使用
        t.column1=ISNULL(@param1,t.column1)
        ,在这种情况下,即使在
        t.column2
        上找到匹配项,也会忽略该行。对于这种情况,我认为将
        更改为
        可能有效。