SELECT LENGTH('*'||CHR(255)||CHR(255)||'$')
FROM DUAL;
此查询给出2而不是4的输出?
但是
SELECT LENGTH(CHR(255)||CHR(255))
FROM DUAL;
此查询给出的输出为null
。这意味着CHR(255)||CHR(255)
表示的字符串是长度为0的空字符串。
CHR(255)
如何影响长度?
答案 0 :(得分:5)
串联字符串中的chr(255)
被视为空,没有长度,因此只计算其他非空字符-因此它得到2而不是4。
ASCII不会真正达到255,并且您实际上并没有处理ASCII。您的数据库字符集是(大概)AL32UTF8,它是一个多字节字符集。来自FileFormat.Info's summary:
对于等于或小于127(十六进制0x7F)的任何字符,UTF-8表示形式为一个字节。它只是完整unicode值的最低7位。这也与ASCII值相同。
对于等于或小于2047(十六进制0x07FF)的字符,UTF-8表示形式跨两个字节。第一个字节将设置两个高位,第三个位清零(即0xC2至0xDF)。第二个字节将设置高位,第二个位将清零(即0x80至0xBF)。
根据文档for chr()
:
对于多字节字符集, n 必须解析为一个完整的代码点。无效的代码点未得到验证,并且指定无效代码点的结果不确定。
对于UTF8,没有完整的代码点255 / FF,因此chr(255)
无效。实际上,according to the spec没有使用FF八位位组的代码点。
您可能希望它呈现为“ÿ”;如果您使用的编码有效,例如AL16UTF16:
select chr(255 using nchar_cs), dump(chr(255 using nchar_cs), 1016) as chr_dump,
unistr('\00ff'), dump(unistr('\00ff'), 1016) as unistr_dump
from dual;
C CHR_DUMP U UNISTR_DUMP
- ---------------------------------------- - --------------------------------------------------
ÿ Typ=1 Len=2 CharacterSet=AL16UTF16: 0,ff ÿ Typ=1 Len=2 CharacterSet=AL16UTF16: 0,ff
但是由于UTF8的编码方式(以及127以上的所有内容)实际上是多个字节,C3BF
。
更有趣的是Oracle如何处理该无效字符。您可以单独看到它的存在并且无效,但是当它与另一个(有效或无效)字符连接时,基本上就被忽略了:
with t (descr, str) as (
select 'chr(255)', chr(255) from dual
union all select 'chr(255)||chr(255)', chr(255)||chr(255) from dual
union all select q'['*'||chr(255)]', '*'||chr(255) from dual
union all select q'[chr(255)||'$']', chr(255)||'$' from dual
union all select q'['*'||chr(255)||'$']', '*'||chr(255)||'$' from dual
union all select q'['*'||chr(255)||'$'||chr(255)]', '*'||chr(255)||'$'||chr(255) from dual
union all select q'[chr(255)||'*'||chr(255)||'$']', chr(255)||'*'||chr(255)||'$' from dual
union all select q'['*'||chr(255)||chr(255)||'$']', '*'||chr(255)||chr(255)||'$' from dual
union all select q'['ÿ']', 'ÿ' from dual
union all select 'chr(127)||chr(127)', chr(127)||chr(127) from dual
union all select 'chr(127)||chr(128)', chr(127)||chr(128) from dual
union all select 'chr(128)||chr(127)', chr(128)||chr(127) from dual
union all select 'chr(128)||chr(128)', chr(128)||chr(128) from dual
)
select descr, str, dump(str, 1016) as str_dump, length(str) as str_length
from t;
DESCR ST STR_DUMP STR_LENGTH
---------------------------- -- -------------------------------------------------- ----------
chr(255) ? Typ=1 Len=1 CharacterSet=AL32UTF8: ff 1
chr(255)||chr(255) NULL
'*'||chr(255) * Typ=1 Len=1 CharacterSet=AL32UTF8: 2a 1
chr(255)||'$' $ Typ=1 Len=1 CharacterSet=AL32UTF8: 24 1
'*'||chr(255)||'$' *$ Typ=1 Len=2 CharacterSet=AL32UTF8: 2a,24 2
'*'||chr(255)||'$'||chr(255) *$ Typ=1 Len=2 CharacterSet=AL32UTF8: 2a,24 2
chr(255)||'*'||chr(255)||'$' *$ Typ=1 Len=2 CharacterSet=AL32UTF8: 2a,24 2
'*'||chr(255)||chr(255)||'$' *$ Typ=1 Len=2 CharacterSet=AL32UTF8: 2a,24 2
'ÿ' ÿ Typ=1 Len=2 CharacterSet=AL32UTF8: c3,bf 1
chr(127)||chr(127) Typ=1 Len=2 CharacterSet=AL32UTF8: 7f,7f 2
chr(127)||chr(128) Typ=1 Len=1 CharacterSet=AL32UTF8: 7f 1
chr(128)||chr(127) Typ=1 Len=1 CharacterSet=AL32UTF8: 7f 1
chr(128)||chr(128) NULL
最后几个例子显示这不是特定于255的问题,而是高于127的问题,这是因为UTF8从127 / 7F(仍然是一个字节)跳到128 / C280(两个字节)。 (例如,您可以看到跳跃here。)
这是一个快速演示,将使用128-255形成的任何无效字符串联在一起,无论与以下哪一种串联都被视为null:
with t (n) as (
select level from dual connect by level <= 255
)
select count(*), min(t1.n), max(t1.n), min(t1.n), max(t2.n)
from t t1
cross join t t2
where chr(t1.n)||chr(t2.n) is null
order by t1.n, t2.n;
COUNT(*) MIN(T1.N) MAX(T1.N) MIN(T1.N) MAX(T2.N)
---------- ---------- ---------- ---------- ----------
16384 128 255 128 255
答案 1 :(得分:0)
255在utf-8编码中不是有效的隔离字节,但实际上是有效的unicode代码点。
问题是chr(255)在Oracle中是什么意思?它是第255个Unicode代码点吗?还是对0x11111111字节的引用。当然,这取决于所讨论的字符集。
select
length (chr(255) || chr(255)), -- NULL
lengthb(chr(255) || chr(255)), -- NULL
length (nchr(255)||nchr(255)), -- 2 valid unicode characters
lengthb(nchr(255)||nchr(255)) -- 4 bytes (in AL32UTF8)
from dual;
要编写可移植的sql语句,强烈建议仅在(0..127)上使用CHR,并且不要在查询中写入CHR(255)。如果需要Unicode字符,则使用CHR坚持使用ASCII或移至NCHR。