数据库: 我有一个Oracle11g数据库,其中包含大约1000万行的表,大约有40列。这些数据源自穿孔卡时代,并已从一个Oracle版本转换为下一个版本。这是一个实时生产数据库,并在一定程度上连续使用。但它不是那么重要(特别是在夜间),我不能用昂贵的查询和更新来应对它。所以没关系。
编辑:Charset是AL32UTF8。
问题: 我注意到有些列包含NUL字符。我发现由1-4个NUL字符组成的值,但理论上可以有多个字符,而不是该列可用的字符数。我想摆脱NUL角色。如果值中只有NUL字符,我想将列的值更改为SQL NULL。如果其他字符之间有NUL字符(我没有看到任何情况)我想删除它们(替换为“”)。
我尝试了什么:
我注意到select rawtohex(mycolumn) from mytable
返回例如'000000'(3个NUL字符)。
select rawtohex('A') from dual;
返回'61'
select rawtohex('Ä') from dual;
返回'C385'。
我已经探索过像这样找到NUL字符:
SELECT DISTINCT mycolumn
FROM mytable
WHERE rawtohex(mycolumn) LIKE '%00%;'
到目前为止,我还没有找到任何包含rawtohex包含'00'的字符的列,除了只有NUL字符的列。所以看起来使用LIKE '%00%'
是安全的。但我不确定rawtohex的oracle实现以及它使用的十六进制编码。
所以...当我继续探索这条路径并最终编写一个脚本来修复垃圾时,我问是否有人之前遇到过这个工作,你是如何解决它的。 :)
答案 0 :(得分:4)
我个人会使用CHR()
来识别零值。 nul是ASCII 0,CHR()
将返回您传入的数字的字符表示。
SQL> with the_data as (
2 select 'a' || chr(0) || 'b' as str from dual
3 union all
4 select 'a' || 'c' from dual
5 )
6 select dump(str)
7 from the_data
8 where str like '%' || chr(0) || '%'
9 ;
DUMP(STR)
----------------------------------------------------
Typ=1 Len=3: 97,0,98
正如您可以通过在CHR(0)
周围连接百分比符号(相当于nul),您可以返回带有nul的行。
DUMP()
返回数据类型(1 means VARCHAR2)字符串的长度(以字节为单位)和数据的内部表示形式;默认为二进制。
但是,您需要注意多字节数据,因为CHR()
会返回相当于该数字模数256的字符:
SQL> with the_data as (
2 select 'a' || chr(0) || 'b' as str from dual
3 union all
4 select 'a' || chr(256) || 'c' from dual
5 )
6 select dump(str)
7 from the_data
8 where str like '%' || chr(0) || '%'
9 ;
DUMP(STR)
-------------------------------------------------
Typ=1 Len=3: 97,0,98
Typ=1 Len=4: 97,1,0,99
正如您所看到的,使用CHR()
或DUMP()
换句话说,如果您没有多字节数据,那么最简单的方法就是replace它:
update <table>
set <column> = replace(<column>, chr(0));
利用RAWTOHEX()
有类似的问题;虽然你可以找到00
,但不能保证它实际上是一个零点:
SQL> with the_data as (
2 select 'a' || chr(0) || 'b' as str from dual
3 union all
4 select 'a' || chr(256) || 'c' from dual
5 )
6 select rawtohex(str)
7 from the_data
8 where str like '%' || chr(0) || '%'
9 ;
RAWTOHEX
--------
610062
61010063
它实际上还有一个问题;假设您有两个字符10
和06
,则返回的值为1006
,您会找到00
。如果您要使用此方法,则必须确保仅从字符串的开头查看两个字符组。
由于nul字符的内部表示用于表示其他多字节字符的部分,因此您不能只替换它们,因为您不知道它是一个字符还是半个字符。所以,如果你使用多字节字符集,据我所知,你将无法做到这一点。
答案 1 :(得分:0)
您可以使用替换功能删除 nul 字符。
替换(FIELD,CHR(0),'')
此 null 值将转换为真实的 null 。
最诚挚的问候,