在Oracle中进行不区分大小写的搜索

ser*_*nni 213 sql oracle case-sensitive case-insensitive sql-like

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

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

Ben*_*Ben 288

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

最终,您选择的方法取决于您的个人情况; 要记住的主要事情是,为了提高性能,您必须正确索引以进行不区分大小写的搜索.

1.对你的专栏和你的字符串进行相同的处理.

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

select * from my_table where upper(column_1) = upper('my_string');
Run Code Online (Sandbox Code Playgroud)

要么

select * from my_table where lower(column_1) = lower('my_string');
Run Code Online (Sandbox Code Playgroud)

如果column_1未编入索引,upper(column_1)或者lower(column_1)视情况而定,则可能会强制进行全表扫描.为了避免这种情况,您可以创建基于函数的索引.

create index my_index on my_table ( lower(column_1) );
Run Code Online (Sandbox Code Playgroud)

如果你正在使用LIKE,那么你必须连接%你正在搜索的字符串.

select * from my_table where lower(column_1) LIKE lower('my_string') || '%';
Run Code Online (Sandbox Code Playgroud)

这个SQL小提琴演示了所有这些查询中发生的事情.请注意解释计划,它指示何时使用索引以及何时使用索引.

2.使用正则表达式.

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

要将此作为相等运算符使用,必须指定字符串的开头和结尾,用克拉和美元符号表示.

select * from my_table where regexp_like(column_1, '^my_string$', 'i');
Run Code Online (Sandbox Code Playgroud)

为了执行LIKE的等效,可以删除这些.

select * from my_table where regexp_like(column_1, 'my_string', 'i');
Run Code Online (Sandbox Code Playgroud)

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

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

3.在会话级别更改它.

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

alter session set nls_sort=BINARY_CI
Run Code Online (Sandbox Code Playgroud)

如果您想指定不同的语言,或者使用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
Run Code Online (Sandbox Code Playgroud)

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

create index my_linguistc_index on my_table 
   (NLSSORT(column_1, 'NLS_SORT = BINARY_CI'));
Run Code Online (Sandbox Code Playgroud)

  • 我可以问一下为什么 `select * from my_table where lower(column_1) LIKE lower('my_string') || 不同 '%';` 而不是 `select * from my_table where lower(column_1) LIKE lower('my_string%');` ?它有什么好处吗? (3认同)
  • 一个原因是,如果您的查询是参数化的(可能在大多数情况下),那么您的调用代码不需要总是在@lopezvit 的末尾连接 %。 (2认同)
  • 如果有一些字符会弄乱“regexp_like”的结果,有没有办法转义这些字符串?举个例子,如果字符串中有$,输出将不是我们期望的那样。//抄送@Ben和其他人请分享。 (2认同)
  • `\``[是转义字符](http://docs.oracle.com/database/121/SQLRF/ap_posix001.htm#SQLRF55540)@bozzmob.如果正则表达式操作的字符串包含`$`,则输出应该没有区别,如果你的正则表达式中需要一个`$`字面值,这可能只会导致问题.如果你有一个特定的问题我会问另一个问题,如果这个评论/答案没有帮助. (2认同)

Álv*_*lez 77

从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
Run Code Online (Sandbox Code Playgroud)

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

create index
   nlsci1_gen_person
on
   MY_PERSON
   (NLSSORT
      (PERSON_LAST_NAME, 'NLS_SORT=BINARY_CI')
   )
;
Run Code Online (Sandbox Code Playgroud)

此信息来自Oracle不区分大小写的搜索.文章提到REGEXP_LIKE但它似乎=也很好用.


在10gR2以上的版本中,它无法真正完成,如果您不需要不区分重复性的搜索,通常的方法就是UPPER()列和搜索表达式.


V4V*_*tta 49

也许你可以尝试使用

SELECT user_name
FROM user_master
WHERE upper(user_name) LIKE '%ME%'
Run Code Online (Sandbox Code Playgroud)

  • 您是否考虑过`WHERE upper(user_name)LIKE UPPER('%ME%')` :) (13认同)
  • @ V4Vendetta使用`upper`函数丢失索引,你知道如何使用索引进行搜索吗? (5认同)
  • 当输入参数是整个大写时它可以工作,如果输入参数是整数大写,它可以工作 (3认同)
  • @sergionni你必须大写搜索词! (3认同)
  • @sergionni,那你为什么不在输入参数上使用`UPPER`呢? (3认同)
  • 对于没有基于函数的索引的大型记录集来说,这将是**非常慢**。 (2认同)

Luk*_*zda 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"
*/
Run Code Online (Sandbox Code Playgroud)

db <> fiddle演示


小智 7

如果将 COLLATE 运算符放在表达式的末尾,它也可以工作,这对我来说似乎更干净。所以你可以使用这个:

WHERE name LIKE 'j%' COLLATE BINARY_CI 
Run Code Online (Sandbox Code Playgroud)

而不是这个:

WHERE name COLLATE BINARY_CI LIKE 'j%'
Run Code Online (Sandbox Code Playgroud)

无论如何,我喜欢 COLLATE 运算符解决方案,原因如下:

  • 您只需在表达式中放置一次,无需担心多个 UPPER 或 LOWER 以及将它们放在哪里
  • 它与您需要的确切语句和表达式隔离,这与 ALTER SESSION 解决方案不同,ALTER SESSION 解决方案使其适用于所有内容。无论数据库或会话 NLS_SORT 设置如何,您的查询都将一致地工作。