Oracle 11g中ORDER BY与MIN()函数结果不一致的原因排查
问题描述
首先创建测试表并插入数据:
CREATE TABLE samuel(id varchar(1), field varchar(1)); INSERT INTO samuel VALUES ('1', ' '); INSERT INTO samuel VALUES ('2', '&');
在Oracle 11.2.0.4.0环境中执行排序查询:
SELECT id, field, DUMP(field) FROM samuel order by field;
得到结果:
| ID | FIELD | DUMP |
|---|---|---|
| 2 | & | Typ=1 Len=1: 38 |
| 1 | Typ=1 Len=1: 32 |
但执行以下查询时,返回结果为1:
select id from samuel where field=(select min(field) from samuel);
当前NLS设置如下:
| PARAMETER | VALUE |
|---|---|
| NLS_LANGUAGE | FRENCH |
| NLS_TERRITORY | FRANCE |
| NLS_CURRENCY | € |
| NLS_ISO_CURRENCY | FRANCE |
| NLS_NUMERIC_CHARACTERS | , |
| NLS_CALENDAR | GREGORIAN |
| NLS_DATE_FORMAT | DD/MM/YYYY HH24:MI:SS |
| NLS_DATE_LANGUAGE | FRENCH |
| NLS_SORT | FRENCH |
| NLS_TIME_FORMAT | HH24:MI:SSXFF |
| NLS_TIMESTAMP_FORMAT | DD/MM/YYYY HH24:MI:SSXFF |
| NLS_TIME_TZ_FORMAT | HH24:MI:SSXFF TZR |
| NLS_TIMESTAMP_TZ_FORMAT | DD/MM/YYYY HH24:MI:SSXFF TZR |
| NLS_DUAL_CURRENCY | € |
| NLS_COMP | BINARY |
| NLS_LENGTH_SEMANTICS | BYTE |
| NLS_NCHAR_CONV_EXCP | FALSE |
请问出现这种结果不一致的原因是什么?
原因分析
这个差异的核心是Oracle对ORDER BY和聚合函数MIN()的排序规则应用逻辑不同,结合你的NLS设置可以拆解为两点:
ORDER BY遵循NLS_SORT指定的语言排序规则
你的NLS_SORT=FRENCH,法语排序规则中,空格(ASCII 32)的排序优先级高于&(ASCII 38),所以ORDER BY field会把&排在前面、空格排在后面,和你看到的排序结果一致。MIN()这类聚合函数使用二进制排序逻辑
尽管NLS_SORT=FRENCH,但你的NLS_COMP=BINARY,Oracle在处理MIN()/MAX()这类聚合函数时,会忽略NLS_SORT的语言排序设置,直接按字符的二进制ASCII码值比较。空格的ASCII码32小于&的ASCII码38,所以MIN(field)返回的是空格对应的字段,最终查询结果为ID=1。
简单来说:ORDER BY用的是语言规则排序,MIN()用的是二进制值排序,两者逻辑不一致,导致了结果差异。
内容的提问来源于stack exchange,提问作者Samuel
相关产品推荐
相关产品推荐

