2014-05-23 15 views
0

我试图在DB2数据库上以UTF8格式存储Unicode字符。我已经确认charset是1208,并且数据库被指定保存为UTF8。DB2 UTF-8数据存储 - 无关字节值

但是,当查询一些unicode数据时,我会得到奇怪的结果。

select hex(firstname), firstname, from my_schema.my_table where my_pk = 1234; 

的结果如下:

C383C289 Ã 

在结果的字符显示的是错误的。从我所收集的数据来看,它是由十六进制值“C383C289”表示的。插入时发送的实际字符为É,并应以UTF8的形式表示为C389。

在这个阶段,我假设它可能是我用来查询解释错误的数据的程序。但是十六进制值(第一个结果列)在多大程度上是错误的?它们在实际字节之间似乎没有使用绒毛“83C2”。或者,“C383C289”实际上是否正确,并且有些UTF8解码引擎无法处理绒毛?这对我来说似乎不太可能。

客户端(DB2 For Toad和WinSQL)都将字符显示为以UTF8表示为C383的字符。

*编辑。我在CLI上测试过,它正确地返回了É字符。我错过了什么吗? “十六进制”函数是否返回了它不应该是的东西?

+1

看起来你的插入过程在某种程度上被打乱了。如果正确存储'É',十六进制值将是C383。 – mustaccio

+0

@mustaccio C383是A,而不是E.注意,我刚刚从DB2 CLI进行了测试,似乎它以某种方式返回了E。 –

+0

对不起,我的意思是C389 – mustaccio

回答

1

在UTF-8 É(U + 00C9)是0xC3 0x89

Ã(U + 00C3)以UTF-8格式为0xC3 0x83。使用UTF-8的

(U + 0089)是0xC2 0x89

这意味着您的插入代码采用É,将其编码为UTF-8字节0xC3 0x89,然后再将这些八位字节插入到DB中。 DB将它们解释为单个字符0xC30x89,并将它们第二次编码为UTF-8,从而生成0xC3 0x83 0xC2 0x89

您需要修复插入代码以不再执行初始编码,因此数据库将按原样看到原始É,而不是它的预编码版本。由于你没有显示你的实际插入代码,所以你真正做到这一点是任何人的猜测。

+0

谢谢,这就是导致问题的原因。具有讽刺意味的是,当数据库采用拉丁-1编码时,它曾经工作得很好,当我们切换到UTF8时,这个问题只会在我们身上徘徊。 –

+1

对,因为Latin-1将大部分Unicode代码点按原样编码为U + 00FF以下的值。例如,Latin-1中的'E'(U + 00C9)是'0xC9'。所以数据库看起来正在节省你准确的数据。 –

0

这是不是一个真正的答案,只是为了演示正确的行为:

> db2 "insert into t1 values ('Élan')" 
DB20000I The SQL command completed successfully. 
> db2 select "hex (f1), f1 from t1" 

1   F1 
---------- ----- 
C3896C616E Élan 

    1 record(s) selected.