Oracle使用NLS_SORT和简单的regexp_like令人费解的行为

时间:2009-08-13 12:50:50

标签: regex oracle search

我今天早上从Oracle遇到了一个奇怪的行为......我无法理解为什么它从文档中以这种方式起作用。对于长篇文章我很抱歉,但我想确保我理解。 哦,并确保在回答之前阅读结尾处的注释:)

请求的目标是返回包含1个或多个小写字符的。为了示例,我的表将是:

CREATE TABLE "TEMP_TABLE" 
   ( "VAL" VARCHAR2(4000 BYTE) );
Insert into TEMP_TABLE (VAL) values ('00A00');
Insert into TEMP_TABLE (VAL) values ('00000');
Insert into TEMP_TABLE (VAL) values ('BC000');
Insert into TEMP_TABLE (VAL) values ('ABC00');
Insert into TEMP_TABLE (VAL) values ('AAAAA');
Insert into TEMP_TABLE (VAL) values ('abc00');

使用此SQL请求:

select val, 
case when regexp_like (val, '[a-b]') then 'MATCH' else 'NO' end from temp_table;

如果会话的 NLS_SORT 值设置为BINARY,则oracle返回:

00A00   NO
00000   NO
BC000   NO
ABC00   NO
AAAAA   NO
abc00   MATCH

=>这里一切都很好:唯一包含小写字母的单词匹配;其他人没有。

但是如果 NLS_SORT 设置为FRENCH,结果就不那么容易理解了:

00A00   NO
00000   NO
BC000   MATCH
ABC00   MATCH
AAAAA   NO
abc00   MATCH

根据我的推断,当有字符而不是A 时,正则表达式匹配。

所以我的问题是:为什么Oracle会将[a-z]理解为'字母不是A'的行?

注1:规格: 该数据库位于Oracle 10G(r2)下,会话的NLS参数如下:

NLS_CALENDAR    GREGORIAN
NLS_COMP        BINARY
NLS_CURRENCY    ¿
NLS_DATE_FORMAT DD/MM/RR HH24:MI
NLS_DATE_LANGUAGE   FRENCH
NLS_DUAL_CURRENCY   ¿
NLS_ISO_CURRENCY    FRANCE
NLS_LANGUAGE    FRENCH
NLS_LENGTH_SEMANTICS    BYTE
NLS_NCHAR_CONV_EXCP FALSE
NLS_NUMERIC_CHARACTERS  , 
NLS_SORT    FRENCH_M
NLS_TERRITORY   FRANCE
NLS_TIME_FORMAT HH24:MI:SSXFF
NLS_TIMESTAMP_FORMAT    DD/MM/RR HH24:MI:SSXFF
NLS_TIMESTAMP_TZ_FORMAT DD/MM/RR HH24:MI:SSXFF TZR
NLS_TIME_TZ_FORMAT  HH24:MI:SSXFF TZR

注2:是的,我可以使用regexp_like(val,'[[:lower:]]')。但是我后来发现了这一点,并没有解释这种奇怪的行为。

1 个答案:

答案 0 :(得分:3)

无论好坏,nls_sort定义的排序顺序用于评估[a-z] regexp。如果您将a,b,c,A,B和C插入temp_table并在每个设置下对其进行排序,您将获得以下内容:

SQL> alter session set nls_sort=BINARY;

Session altered.

SQL> select val,
  2  case when regexp_like (val, '[a-z]') then 'MATCH' else 'NO' end m
  3  from temp_table order by val;

VAL           M
------------------------- -------------------------
A             NO
B             NO
C             NO
a             MATCH
b             MATCH
c             MATCH

6 rows selected.

SQL> alter session set nls_sort=FRENCH;

Session altered.

SQL> select val,
  2  case when regexp_like (val, '[a-z]') then 'MATCH' else 'NO' end m
  3  from temp_table order by val;

VAL           M
------------------------- -------------------------
A             NO
a             MATCH
B             MATCH
b             MATCH
C             MATCH
c             MATCH

6 rows selected.

由于大写字母与法语设置中的小写字母“交错”,因此在Oracle的实现中评估为true。