kau*_*nav 1 sql string oracle ascii character-encoding
SELECT LENGTH('*'||CHR(255)||CHR(255)||'$')
FROM DUAL;
Run Code Online (Sandbox Code Playgroud)
此查询的输出为2而不是4?
但
SELECT LENGTH(CHR(255)||CHR(255))
FROM DUAL;
Run Code Online (Sandbox Code Playgroud)
此查询将输出作为null.这意味着由...表示的字符串CHR(255)||CHR(255)是一个长度为0的空字符串.
这CHR(255)对长度有何影响?
在chr(255)您的串接字符串中被视为无效,不具有长度,所以只有其他非空字符计数-因此它得到2,而不是4.
ASCII实际上并没有达到255,你并没有真正处理ASCII.您的数据库字符集(大概)是AL32UTF8,它是一个多字节字符集.从FileFormat.Info的摘要:
对于任何等于或低于127(十六进制0x7F)的字符,UTF-8表示是一个字节.它只是完整unicode值的最低7位.这也与ASCII值相同.
对于等于或低于2047(十六进制0x07FF)的字符,UTF-8表示分布在两个字节上.第一个字节将设置两个高位,第三个位清零(即0xC2至0xDF).第二个字节的顶部位置1,第二个字位置清零(即0x80至0xBF).
而从文档为chr():
对于多字节字符集,n必须解析为整个代码点.无效的代码点无效,指定无效代码点的结果是不确定的.
对于UTF8,没有整个代码点255/FF,因此chr(255)无效.实际上,根据规范,没有带有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
Run Code Online (Sandbox Code Playgroud)
但由于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
Run Code Online (Sandbox Code Playgroud)
最后几个例子显示这不是特定于255,它是127以上的任何问题,因为UTF8从127/7F(仍然是单个字节)跳转到128/C280(两个字节).(例如,你可以在这里看到跳转.)
这里是一个快速演示,连接使用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
Run Code Online (Sandbox Code Playgroud)