【问题标题】:Use of SqlParameter in SQL LIKE clause not working在 SQL LIKE 子句中使用 SqlParameter 不起作用
【发布时间】:2010-10-14 11:42:46
【问题描述】:

我有以下代码:

const string Sql = 
    @"select distinct [name] 
      from tblCustomers 
      left outer join tblCustomerInfo on tblCustomers.Id = tblCustomerInfo.CustomerId  
      where (tblCustomer.Name LIKE '%@SEARCH%' OR tblCustomerInfo.Info LIKE '%@SEARCH%');";

using (var command = new SqlCommand(Sql, Connection))
{       
    command.Parameters.AddWithValue("@SEARCH", searchString);
    ...
}

这个不行,我也试过了:

const string Sql = 
    @"select distinct [name] 
     from tblCustomers 
     left outer join tblCustomerInfo on tblCustomers.Id = tblCustomerInfo.CustomerId  
     where (tblCustomer.Name LIKE @SEARCH OR tblCustomerInfo.Info LIKE @SEARCH );";

using (var command = new SqlCommand(Sql, Connection))
{       
    command.Parameters.AddWithValue("@SEARCH", "'%" + searchString + "%'");
    ...
}

但这也不起作用。出了什么问题?有什么建议吗?

【问题讨论】:

    标签: c# sql-server tsql ado.net sql-like


    【解决方案1】:

    你想要的是:

    tblCustomerInfo.Info LIKE '%' + @SEARCH + '%'
    

    (或编辑参数值以首先包含 %)。

    否则,您要么(第一个示例)搜索 literal“@SEARCH”(而不是 arg 值),要么在查询中嵌入一些额外的引号(第二个示例)。

    在某些方面,让 TSQL 使用 LIKE @SEARCH 并在调用者处处理它可能更容易:

    command.Parameters.AddWithValue("@SEARCH","%" + searchString + "%");
    

    任何一种方法都应该有效。

    【讨论】:

    • command.Parameters.AddWithValue("@SEARCH","%" + searchString + "%");工作,额外的单引号是你指出的问题
    • 第二种方式对我来说看起来更好,因为最后的陈述确实看起来很整洁。
    • 当 searchString 包含字符 % _ 或 [ 时,这将无法正常工作,假设您要实际搜索这些字符文字之一。对于 100% 的解决方案,您需要将这些字符包含在 searchString 中的括号 [] 中。 C# 代码 Regex.Replace(searchString, @"([%_\[])", @"[$1]") 可以解决问题。
    • @MattMiller 只会将 searchString 包裹在方括号 command.Parameters.AddWithValue("@SEARCH","%[" + searchString + "]%"); 中,而不是正则表达式不起作用?
    • @ThabisoMofokeng 不,括号不像引号(除非它包含单个字符)。括号在 SQL LIKE 中的作用是告诉它匹配其中的任何字符,例如 'a[123]z' 匹配 'a1z'、'a2z' 和 'a3z' 但不匹配 'a12z' 因为括号表达式只匹配一个字符。我建议使用正则表达式将每个特殊字符括在括号中,这会强制 LIKE 逐字匹配这些字符。
    【解决方案2】:

    而不是使用:

    const string Sql = 
    @"select distinct [name] 
      from tblCustomers 
      left outer join tblCustomerInfo on tblCustomers.Id = tblCustomerInfo.CustomerId  
      where (tblCustomer.Name LIKE '%@SEARCH%' OR tblCustomerInfo.Info LIKE '%@SEARCH%');";
    

    使用此代码:

    const string Sql = 
    @"select distinct [name] 
      from tblCustomers 
      left outer join tblCustomerInfo on tblCustomers.Id = tblCustomerInfo.CustomerId  
      where (tblCustomer.Name LIKE '%' + @SEARCH + '%' OR tblCustomerInfo.Info LIKE '%' + @SEARCH + '%');";
    

    【讨论】:

    • 这对我来说没有任何意义,但它确实有效。你能解释一下原因吗?
    • (@需要在 cmets 中转义) @SEARCH 参数转换为 SQL varchar,然后与 % 字符连接,最后在 LIKE 语句上进行比较。对于 ex \@SEARCH val "Joan",变成:tblCustomer.Name LIKE '%' + 'Joan' + '%',注意这里的 'Joan' 完全转义,-> tblCustomer.Name LIKE '%Joan% '。如果搜索参数包含任何意外字符(% 或 ',它们将被转义,给定 \@SEARCH = "%Ji'm"。tblCustomer.Name LIKE '%' + '[%]Ji''m' + ' %'. => '%[%]Ji''m%' (% 用方括号转义,单引号用加倍转义)。
    • 使用字符串插值时,您甚至不需要转义单引号:var query = $"SELECT * FROM Customer LIKE '%' + {parameterValue} + '%'"; 我建议首先在 T-SQL 中使用 sql 变量进行测试:DECLARE @parameterValue VARCHAR(10) = 'Cust';SELECT * FROM Customer LIKE '%' + @parameterValue + '%'
    • @Misi 在此处使用字符串插值会产生 SQL 注入漏洞。始终使用 Sql 参数。
    【解决方案3】:

    请注意 Add 和 AddWithValue 方法之间的细微差别。当我使用 Add 方法并输入错误的 SqlType 参数时,我遇到了以下问题。

    • nchar 和 nvarchar 可以存储 Unicode 字符。
    • char 和 varchar 无法存储 Unicode 字符。

    例如:

    string query = " ... WHERE stLogin LIKE @LOGIN ";
    
    SqlParameter p = new SqlParameter("@LOGIN", SqlDbType.Char, 255) 
    { 
        Value = "%" + login + "%" 
    };
    
    command.Parameters.AddWithValue(p.ParameterName, p.Value); //works fine!!!
    
    command.Parameters.Add(p); // won't work
    

    当我将 SqlType 更改为 NVarChar 时,这两种方法对我来说都很好。

    SqlParameter p = new SqlParameter("@LOGIN", SqlDbType.NVarChar, 255) 
    { 
        Value = "%" + login + "%" 
    };
    
    command.Parameters.AddWithValue(p.ParameterName, p.Value); //worked fine!!!
    
    command.Parameters.Add(p); //worked fine!!!
    

    【讨论】:

    • 我认为第一个示例没有按预期工作的原因是因为您指定了列类型。如果您使用带有参数名称和值的构造函数,它应该可以按预期工作。查看 AddWithValue 的源代码,他们所做的只是调用带有参数名称和值的构造函数。所以: p = new SqlParameter("@LOGIN", "%" + login + "%"); command.Parameters.Add(p);
    【解决方案4】:

    你可以做 LIKE @SEARCH 并在你的 C# 代码中做

    searchString = "%" + searchString + "%"
    

    【讨论】:

    • 这不会暴露sql注入的机会吗?
    • 是的。或者,更有可能的是,有人要搜索包含 ' 字符的字符串,它会爆炸。不要这样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-25
    • 2012-11-15
    • 1970-01-01
    • 2019-04-30
    • 2013-11-05
    • 1970-01-01
    相关资源
    最近更新 更多