SQL Server不区分大小写的查询

6

我希望在使用SQL Server进行查询时,在比较字符串时忽略大小写。目前我能够使用类似以下的方式实现:

SELECT *
FROM Venue
WHERE
   Name COLLATE Latin1_general_CI_AI Like '%cafe%' COLLATE Latin1_general_CI_AI

有没有一种方法可以设置全局指令,以便它影响每个查询? 类似于这样:
SET COLLATE Latin1_general_CI_AI;
SELECT *
    FROM Venue
    WHERE
       Name Like '%this%';
SELECT *
    FROM Venue
    WHERE
       Name Like '%that%';
...

感谢您!

2
你不能将数据库的排序规则设置为不区分大小写吗?(https://msdn.microsoft.com/zh-cn/library/ms175835(v=sql.110).aspx) - Veatch
1
或者,您可以将表中单个列的排序规则设置为与数据库的排序规则不同。如何设置列排序规则 - DeadZone
很不幸,用户想在每次查询之前选择是否忽略大小写。 - Daniel Teleginski Camargo
2
相关问题:https://dev59.com/12w05IYBdhLWcg3wfh2g - dugas
我发现最简单的方法是使用UPPER或LOWER函数来比较数据,如果你没有更改排序规则的权限。我以前曾经与大小写敏感的数据库一起工作过。我理解你的痛苦! - NonProgrammer
1个回答

4
有没有一种方法可以设置全局指令,以便影响每个查询?
没有。
排序规则不是应用于查询的会话属性,也不能动态更改。这个请求的另一个问题是大小写敏感性不是可以单独启用或禁用的选项:它是排序规则的一个属性,就像重音敏感性、宽度敏感性、特定字母表排列顺序等。一个查询可以比较多个字段,每个字段都有不同的排序规则。因此,即使您可以设置一个会话中有效的排序规则,这可能会强制转换其他排序规则的列在没有被请求为大小写不敏感的情况下即时转换排序规则。全局会话设置也会影响排序(例如 TOP(n)、ORDER BY 等),而不仅仅是比较。
由于问题在于用户想要每次执行时确定是否忽略排序规则的一部分,因此有几个选项,但所有选项都会产生一定的性能损失:
  1. Construct the query (or queries) in Dynamic SQL:

    DECLARE @SQL NVARCHAR(MAX),
            @Collation NVARCHAR(50);
    
    SET @Collation = '';
    IF (@CaseInsensitive = 1)
    BEGIN
      SET @Collation = N'COLLATE Latin1_general_CI_AI';
    END;
    
    SET @SQL = N'SELECT *
      FROM Venue
      WHERE Name ' + @Collation + N' LIKE ''%' + @SearchParam
                   + N'%'' ' + @Collation;
    
    EXEC(@SQL);
    
  2. Translate each character into upper-case and lower-case pairs in single-character ranges. This can be done in the app layer for the parameter value being searched on:

    • For default case-sensitive (don't do anything):
      @SearchParam = 'This'
    • For case-insensitive:
      @SearchParam = '[tT][hH][iI][sS]'
  3. Force everything to the same case. Assume that the option to do case-insensitive is an additional parameter that is passed in:

    SELECT *
    FROM Venue
    WHERE CASE @CaseInsensitive
            WHEN 1 THEN LOWER(Name)
            ELSE Name
          END
             LIKE 
          CASE @CaseInsensitive
            WHEN 1 THEN '%' + LOWER(@SearchParam) + '%'
            ELSE '%' + @SearchParam + '%'
          END;
    

    Or, do the LOWER() prior to the query:

    IF (@CaseInsensitive = 1)
    BEGIN
      SET @SearchParam = LOWER(@SearchParam);
    END;
    
    SELECT *
    FROM Venue
    WHERE CASE @CaseInsensitive
            WHEN 1 THEN LOWER(Name)
            ELSE Name
          END
             LIKE '%' + @SearchParam + '%';
    

2
我会使用第三个变量,并将@SearchParam的处理移出查询本身,这样可以使代码更加简洁。 - Vladimir Baranov
@VladimirBaranov 是的,我考虑过提到 @SearchParam 可以在应用层进行“降级”,但是对于要求调用者/查询实现者有那么多信任感并不太舒服。但是,这仍然是一个需要考虑的选项,所以我将其添加到了 #3 中,并提出了我的担忧。此外,由于 #3 中 CASE 语句可能存在查询优化器问题,我更倾向于选项 #2,但适当的性能测试应该是决定因素 :-)。 - Solomon Rutzky
1
实际上,我考虑在存储过程的开始处在服务器上计算 LOWER(@SearchParam)。在应用程序中执行此操作可能是不正确的(至少在理论上,如果应用程序使用的排序规则与服务器使用的排序规则不完全相同,则应用程序中的 ToLower 的结果可能与服务器上的 LOWER 不同)。当您执行 LIKE '%something%' 时,在任何情况下性能都会非常糟糕。 - Vladimir Baranov
@VladimirBaranov 哦,那就有意义多了 ;-). 我已经再次更新了。 - Solomon Rutzky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接