SQL Server在where表达式中忽略大小写


Answers:


135

在SQL Server数据库的默认配置,字符串比较不区分大小写。如果您的数据库覆盖了此设置(通过使用替代排序规则),则需要指定在查询中使用哪种排序规则。

SELECT * FROM myTable WHERE myField = 'sOmeVal' COLLATE SQL_Latin1_General_CP1_CI_AS

请注意,我提供的排序规则只是一个示例(尽管很可能对您来说很好用)。有关SQL Server排序规则的更详尽概述,请参见此处


只是为了确认,只需在WHERE语句的末尾添加一次,这会影响所有WHERE子句,对吗?
ashleedawg '18年

想知道您的答案是否存在任何性能问题,方法是将列值转换为UPPERLOWER大小写,然后使用LIKE进行搜索?
shaijut

1
@ashleedawg-好问题..它似乎是每行设置。
Leo Gurdian

29

通常,字符串比较不区分大小写。如果您的数据库配置为区分大小写排序规则,则需要强制使用不区分大小写的排序规则:

SELECT balance FROM people WHERE email = 'billg@microsoft.com'
  COLLATE SQL_Latin1_General_CP1_CI_AS 

@AskeB。和Andrejs:从技术上讲,这不是数据库配置问题。请参阅我的答案以澄清字符串比较。
所罗门·鲁兹基

21

我在其他地方找到了另一个解决方案。即使用

upper(@yourString)

但是这里的每个人都在说,在SQL Server中,这没关系,因为它还是忽略大小写吗?我很确定我们的数据库区分大小写。


6
您是对的,可以使数据库区分大小写是正确的,但是即使需要它,效率也很低。COLLATE是要使用的关键字。
mjaggard 2012年

1
感谢您提出来,@ mjaggard。我希望您或任何似乎对我的答案不满意的人,为像我这样搜寻并找到我的答案的任何人的利益做好详尽的阐述。
丹尼

1
对此表示支持,因为这是一个完全合理的解释。整理过多的开销,如果您的字符串中包含排序规则无法理解的字符,该怎么办?拉丁1是糟糕的编码方案。如果您的字符串中带有撇号,那么祝您好运获得有意义的结果(例如:O'Brien)。
eggmatters

2
也被推荐。我可以想到很多有用的案例。另外,通常有不止一种做某事的好方法。
Inversus

1
为了比较目的而改变字符串的大小写通常是不好的。在某些语言中,转换不是往返的。即LOWER(x)!= LOWER(UPPER(x))。
Ceisc

14

前2个答案(来自Adam RobinsonAndrejs Cainikovs)在某种程度上说是正确的,因为它们在技术上确实有效,但是它们的解释是错误的,因此在许多情况下可能会引起误解。例如,尽管SQL_Latin1_General_CP1_CI_AS排序规则在许多情况下都可以使用,但不应认为它是适当的不区分大小写的排序规则。实际上,考虑到OP正在使用区分大小写(或可能是二进制)的排序规则在数据库中工作,我们知道OP没有使用许多安装(默认情况下,尤其是操作系统上安装的默认排序规则)的排序规则使用美国英语作为语言)SQL_Latin1_General_CP1_CI_AS。当然,OP可能正在使用SQL_Latin1_General_CP1_CS_AS,但是当与VARCHAR数据,重要的是不要更改代码页,因为这可能会导致数据丢失,并且这受排序规则的区域设置/区域性(即Latin1_General,法语,希伯来语等)控制。请参阅下面的第9点。

其他四个答案在不同程度上都是错误的。

我将在这里澄清所有误解,以便读者希望做出最适当/最有效的选择。

  1. 不要使用UPPER()。那完全是不必要的额外工作。使用COLLATE子句。在任何一种情况下都需要进行字符串比较,但是UPPER()还必须逐个字符地进行检查,以查看是否存在大写映射,然后进行更改。而且您需要在两侧都这样做。添加COLLATE仅指示处理使用与默认情况下不同的规则集来生成排序关键字。正如在此测试脚本(在PasteBin上)证明的COLLATE那样,使用绝对比使用更有效(或者,如果您喜欢这个词,则为“性能” UPPER()

    @Ceisc在@Danny的答案中提到了一个问题:

    在某些语言中,转换不是往返的。即LOWER(x)!= LOWER(UPPER(x))。

    土耳其语大写“İ”是常见的示例。

  2. 不,排序规则不是数据库范围的设置,至少在这种情况下不是这样。有一个数据库级别的默认排序规则,它用作未指定COLLATE子句的更改列和新创建的列的默认排序规则(很可能是这种常见的误解的来源),但是除非您这样做,否则它不会直接影响查询。将字符串文字和变量与其他字符串文字和变量进行比较,或者您正在引用数据库级元数据。

  3. 不,不是按查询排序。

  4. 排序规则是基于谓词(即,某些操作数)或表达式,而不是针对每个查询。对于整个查询,不仅是WHERE子句,都是如此。这包括JOIN,GROUP BY,ORDER BY,PARTITION BY等。

  5. 不,由于以下原因,请不要转换为VARBINARY(例如convert(varbinary, myField) = convert(varbinary, 'sOmeVal')):

    1. 这是一个二进制比较,不区分大小写(这是这个问题的要求)
    2. 如果您确实想要二进制比较,请使用二进制排序规则。使用一个与结束_BIN2,如果你使用的是SQL Server 2008或更新,否则你没有选择,只能使用一个结束与_BIN。如果数据是正确的,NVARCHAR那么使用哪种语言环境都没有关系,因为在这种情况下它们都是相同的,因此Latin1_General_100_BIN2始终有效。如果数据是VARCHAR,你必须使用相同的语言环境中的数据是目前在(如Latin1_GeneralFrenchJapanese_XJIS,等),因为语言环境决定了所使用的代码页,并改变代码页可以改变的数据(即数据丢失)。
    3. 在不指定大小的情况下使用可变长度数据类型将取决于默认大小,根据使用数据类型的上下文,存在两种不同的默认值。字符串类型为1或30。与CONVERT()它一起使用时将使用30个默认值。危险是,如果字符串可以超过30个字节,它将被静默截断,并且您很可能会从该谓词中获得错误的结果。
    4. 即使您想要区分大小写的比较,二进制排序规则也是也不区分大小写(另一个非常常见的误解)。
  6. 不,LIKE并不总是区分大小写的。它使用被引用列的排序规则,或将变量与字符串文字进行比较时使用的数据库排序规则,或通过可选COLLATE子句指定的排序规则。

  7. LCASE不是SQL Server函数。它似乎是Oracle或MySQL。还是Visual Basic?

  8. 由于问题的上下文是将列与字符串文字进行比较,因此实例的排序规则(通常称为“服务器”)或数据库的排序规则都不会对此处产生任何直接影响。排序规则存储在每一列中,并且每一列可以具有不同的排序规则,并且这些排序规则不必与数据库的默认排序规则或实例的排序规则相同。当然,如果COLLATE在创建数据库时未指定子句,则实例排序规则是新创建的数据库将用作默认排序规则的默认排序规则。同样,如果COLLATE未指定子句,则数据库的默认排序规则将是更改后的列或新创建的列将使用的列。

  9. 您应使用不区分大小写的排序规则,否则该排序规则与列的排序规则相同。使用以下查询查找列的排序规则(更改表的名称和架构名称):

    SELECT col.*
    FROM   sys.columns col
    WHERE  col.[object_id] = OBJECT_ID(N'dbo.TableName')
    AND    col.[collation_name] IS NOT NULL;
    

    然后只需将更_CS改为即可_CI。所以,Latin1_General_100_CS_AS将变为Latin1_General_100_CI_AS

    如果该列使用二进制排序规则(以_BIN或结尾_BIN2),则使用以下查询查找类似的排序规则:

    SELECT *
    FROM   sys.fn_helpcollations() col
    WHERE  col.[name] LIKE N'{CurrentCollationMinus"_BIN"}[_]CI[_]%';
    

    例如,假设该列正在使用Japanese_XJIS_100_BIN2,请执行以下操作:

    SELECT *
    FROM   sys.fn_helpcollations() col
    WHERE  col.[name] LIKE N'Japanese_XJIS_100[_]CI[_]%';
    

有关归类,编码等的更多信息,请访问:归类信息


7

不,仅使用LIKE不起作用。LIKE搜索与您的给定模式完全匹配的值。在这种情况下,LIKE只会找到文本“ sOmeVal”,而不是“ someval”。

一个可行的解决方案是使用该LCASE()功能。LCASE('sOmeVal')获取文本的小写字符串:“ someval”。如果在比较的两面都使用此功能,则可以使用:

SELECT * FROM myTable WHERE LCASE(myField) LIKE LCASE('sOmeVal')

该语句比较两个小写字符串,以便您的“ sOmeVal”将与“ someval”的所有其他符号匹配(例如,“ Someval”,“ sOMEVAl”等)。


7
在以_CI排序的99.9%的SQL Server安装中,LIKE不区分大小写。
RichardTheKiwi

1
如今,该函数称为LOWER
David Brossard

@DavidBrossard和David Hermanns,我认为LCASE()SQL Server中从来没有(至少我看不到)。我认为此答案适用于完全不同的RDBMS。请参阅我的答案以澄清字符串比较。
所罗门·鲁兹基

4

您可以强制区分大小写,将其强制转换为这样的varbinary:

SELECT * FROM myTable 
WHERE convert(varbinary, myField) = convert(varbinary, 'sOmeVal')

3
虽然这是可行的,但不是明智的方法。排序规则用于管理排序和字符串比较。
亚当·罗宾逊

@AdamRobinson不是关于“字符串比较”的吗?
Fandango68年

@ Fandango68是的,Adam说在进行字符串比较时排序规则更好。
JLRishe '18年

@ Fandango68这个答案在几个层面上都是错误的。请参阅我的回答对细节,特别是第5点
所罗门Rutzky

@AdamRobinson请参阅我的答案以获取有关字符串比较的说明。
所罗门·鲁兹基

2

您在哪个数据库上?使用MS SQL Server,它是数据库范围的设置,或者您可以使用COLLATE关键字在每个查询中覆盖它。


嗨,您好。对于SQL Server,就此问题而言,它既不是数据库范围的设置,也不是每个查询的问题。请查看我的答案以获取详细信息。
所罗门·鲁茨基
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.