Oracle中不区分大小写的搜索


228

LIKE和其他比较运算符=等的默认行为区分大小写。

是否可以使它们不区分大小写?


友好的提醒是,即使user_name上有索引,某些示例搜索也将导致全表扫描。
JonSG 2011年

8
您是否考虑过使用REGEXP_LIKE(username,'me','i')替代LIKE?
kubanczyk 2012年

5
不,LIKE为我工作正常
sergionni'2

Answers:


82

从10gR2开始,Oracle允许通过设置NLS_COMPNLS_SORT会话参数来微调字符串比较的行为:

SQL> SET HEADING OFF
SQL> SELECT *
  2  FROM NLS_SESSION_PARAMETERS
  3  WHERE PARAMETER IN ('NLS_COMP', 'NLS_SORT');

NLS_SORT
BINARY

NLS_COMP
BINARY


SQL>
SQL> SELECT CASE WHEN 'abc'='ABC' THEN 1 ELSE 0 END AS GOT_MATCH
  2  FROM DUAL;

         0

SQL>
SQL> ALTER SESSION SET NLS_COMP=LINGUISTIC;

Session altered.

SQL> ALTER SESSION SET NLS_SORT=BINARY_CI;

Session altered.

SQL>
SQL> SELECT *
  2  FROM NLS_SESSION_PARAMETERS
  3  WHERE PARAMETER IN ('NLS_COMP', 'NLS_SORT');

NLS_SORT
BINARY_CI

NLS_COMP
LINGUISTIC


SQL>
SQL> SELECT CASE WHEN 'abc'='ABC' THEN 1 ELSE 0 END AS GOT_MATCH
  2  FROM DUAL;

         1

您还可以创建不区分大小写的索引:

create index
   nlsci1_gen_person
on
   MY_PERSON
   (NLSSORT
      (PERSON_LAST_NAME, 'NLS_SORT=BINARY_CI')
   )
;

此信息来自Oracle不区分大小写的搜索。文章提到了,REGEXP_LIKE但似乎也适用于旧版本=


在10gR2之前的版本中,这实际上是不可能完成的,并且如果不需要不需要重音符号的搜索,通常的方法是只UPPER()对列和搜索表达式都使用。


1
这很好用,但是使用LIKE / =运算符的更新非常慢……:(
Saqib Ali

1
@SaqibAli任意LIKE表达式(例如WHERE foo LIKE '%abc%')如果不能被索引已经足够慢,我不认为它与大小写敏感度特别相关。
阿尔瓦罗·冈萨雷斯

1
您也可以在SQLPLUS外部进行设置,例如在shell环境中。例如,在使用中的Perl脚本中DBD::Oracle,您可以$ENV{NLS_SORT} = 'BINARY_CI'; $ENV{NLS_COMP} = 'LINGUISTIC';在调用`DBI-> connect`之前编写。
mivk

嘿,这ALTER SESSION只会更改您的本地更正实例,这是否意味着像您当前的会话,即如果我关闭并重新打开它将会重置。有没有一种方法可以让我看到当前值,因此如果它在所有地方都持续存在,我可以更改回原始设置...
Seabizkit

305

在不使用全文索引的情况下,可以通过3种主要方法在Oracle中执行不区分大小写的搜索。

最终,您选择哪种方法取决于您的个人情况。要记住的主要事情是,为了提高性能,必须为不区分大小写的搜索正确地建立索引。

1.将列和字符串的大小写相同。

您可以使用UPPER()或强制所有数据都使用相同的大小写LOWER()

select * from my_table where upper(column_1) = upper('my_string');

要么

select * from my_table where lower(column_1) = lower('my_string');

如果column_1未在upper(column_1)或上建立索引lower(column_1),则可能会强制执行全表扫描。为了避免这种情况,您可以创建基于函数的index

create index my_index on my_table ( lower(column_1) );

如果您使用的是LIKE,则必须在%要搜索的字符串周围连接一个。

select * from my_table where lower(column_1) LIKE lower('my_string') || '%';

此SQL Fiddle演示了所有这些查询中发生的情况。注意说明计划,该计划指示何时使用索引,何时不使用索引。

2.使用正则表达式。

从Oracle 10g开始REGEXP_LIKE()可用。您可以指定_match_parameter_ 'i',以执行不区分大小写的搜索。

为了将其用作相等运算符,您必须指定字符串的开始和结束,以克拉和美元符号表示。

select * from my_table where regexp_like(column_1, '^my_string$', 'i');

为了执行等效的LIKE,可以将其删除。

select * from my_table where regexp_like(column_1, 'my_string', 'i');

请注意这一点,因为您的字符串可能包含正则表达式引擎将以不同的方式解释的字符。

除了使用REGEXP_LIKE()之外,此SQL Fiddle还显示了相同的示例输出。

3.在会话级别进行更改。

所述NLS_SORT参数控制为排序和各种比较运算符,包括归类序列=和类似物。您可以通过更改会话来指定不区分大小写的二进制排序。这意味着在该会话中执行的每个查询都将执行不区分大小写的参数。

alter session set nls_sort=BINARY_CI

如果要指定其他语言,或者要使用BINARY_AI进行不区分重音的搜索,则还有很多其他信息与语言排序和字符串搜索有关。

您还需要更改NLS_COMP参数。报价:

服从NLS_SORT参数的确切运算符和查询子句取决于NLS_COMP参数的值。如果运算符或子句不遵循NLS_COMP确定的NLS_SORT值,则使用的归类为BINARY。

NLS_COMP的默认值为BINARY;但是,LINGUISTIC指定Oracle应该注意NLS_SORT的值:

WHERE子句和PL / SQL块中所有SQL操作的比较应使用NLS_SORT参数中指定的语言排序。为了提高性能,您还可以在要进行语言比较的列上定义语言索引。

因此,再次,您需要更改会话

alter session set nls_comp=LINGUISTIC

如文档中所述,您可能需要创建语言索引以提高性能

create index my_linguistc_index on my_table 
   (NLSSORT(column_1, 'NLS_SORT = BINARY_CI'));

“创建基于函数的索引”令人惊讶的是,这有什么不同
Jacob Goulden 2015年

请问为什么它是不同的做 select * from my_table where lower(column_1) LIKE lower('my_string') || '%';,而不是 select * from my_table where lower(column_1) LIKE lower('my_string%');?有什么好处吗?
lopezvit '16

1
原因之一是,如果您的查询被参数化(可能在大多数情况下),那么您的调用代码不必总是在@lopezvit末尾连接%。
2016年

1
如果有些字符会弄乱的结果regexp_like,是否有一种方法可以转义此类字符串?举个例子,如果字符串中有$,则输出将不会达到我们的预期。// cc @Ben和其他人请分享。
bozzmob

2
` 是转义字符 @bozzmob。如果正则表达式所处理的字符串包含a $,则输出应该没有差异,这只会在您需要$在正则表达式中使用文字时才引起问题。如果您有特定的问题,如果这个评论/答案没有帮助,我会问另一个问题。
2016年

51

也许你可以尝试使用

SELECT user_name
FROM user_master
WHERE upper(user_name) LIKE '%ME%'

3
当输入参数全部为大写字母时有效,如果较低或混合使用则不起作用
sergionni 2011年

13
那你有想过WHERE upper(user_name) LIKE UPPER('%ME%')吗 :)
Konerak 2011年

3
@sergionni,您还必须大写搜索词!
Markus Winand

3
@sergionni,那你为什么不还要UPPER在输入参数上使用呢?
捷克学2011年

5
@ V4Vendetta使用upper丢失索引的函数,您是否知道如何使用索引进行搜索?
jcho360

7

在Oracle 12c R2中,您可以使用COLLATE operator

COLLATE运算符确定表达式的排序规则。使用此运算符,您可以使用标准归类派生规则来覆盖数据库为该表达式派生的归类。

COLLATE运算符采用一个参数collat​​ion_name,您可以为其指定命名的归类或伪归类。如果排序规则名称包含空格,则必须用双引号将该名称引起来。

演示:

CREATE TABLE tab1(i INT PRIMARY KEY, name VARCHAR2(100));

INSERT INTO tab1(i, name) VALUES (1, 'John');
INSERT INTO tab1(i, name) VALUES (2, 'Joe');
INSERT INTO tab1(i, name) VALUES (3, 'Billy'); 
--========================================================================--
SELECT /*csv*/ *
FROM tab1
WHERE name = 'jOHN' ;
-- no rows selected

SELECT /*csv*/ *
FROM tab1
WHERE name COLLATE BINARY_CI = 'jOHN' ;
/*
"I","NAME"
1,"John"
*/

SELECT /*csv*/ *
FROM tab1 
WHERE name LIKE 'j%';
-- no rows selected

SELECT /*csv*/ *
FROM tab1 
WHERE name COLLATE BINARY_CI LIKE 'j%';
/*
"I","NAME"
1,"John"
2,"Joe"
*/

db <> fiddle演示


2
select user_name
from my_table
where nlssort(user_name, 'NLS_SORT = Latin_CI') = nlssort('%AbC%', 'NLS_SORT = Latin_CI')

%的第一个参数,以你的第二个NLSSORT不是意味着是通配符,对不对?他们有点困惑。
Stefan van den Akker,

1

您可以执行以下操作:

where regexp_like(name, 'string$', 'i');
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.