如何摆脱Oracle数据库中的NUL字符?

时间:2014-06-13 09:29:32

标签: oracle oracle11g

数据库: 我有一个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实现以及它使用的十六进制编码。

所以...当我继续探索这条路径并最终编写一个脚本来修复垃圾时,我问是否有人之前遇到过这个工作,你是如何解决它的。 :)

2 个答案:

答案 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

它实际上还有一个问题;假设您有两个字符1006,则返回的值为1006,您会找到00。如果您要使用此方法,则必须确保仅从字符串的开头查看两个字符组。

由于nul字符的内部表示用于表示其他多字节字符的部分,因此您不能只替换它们,因为您不知道它是一个字符还是半个字符。所以,如果你使用多字节字符集,据我所知,你将无法做到这一点。

答案 1 :(得分:0)

您可以使用替换功能删除 nul 字符。

  

替换(FIELD,CHR(0),'')

null 值将转换为真实的 null

最诚挚的问候,