2017-09-23 51 views
0

我已经从文件中得到了一些日期,并将它插入到数据库Oracle中。编码插入值Oracle

的问题就是一个例子:

  • 列类型VARCHAR2,大小3个字节

  • 我试着插入 'абв',看到了异常:ORA-12899:值过大列(实际:6,最大值:3)

这是因为每个字符都以两个字节编码。好的,现在我们将重新编码。数据库编码为AL32UTF8。该文件的编码是CP866。

的尝试失败重新编码:

Encoding srcEncodingFormat = Encoding.GetEncoding(866); 
Encoding dstEncodingFormat = Encoding.UTF8; 
byte[] originalByteString = srcEncodingFormat.GetBytes(s); 
byte[] convertedByteString = Encoding.Convert(srcEncodingFormat, 
dstEncodingFormat, originalByteString); 
s = dstEncodingFormat.GetString(convertedByteString); 

我们不能改变列类型。我们也不能使用VARCHAR2(3 CHAR)。我该如何解决它?当数据插入数据库时​​,是否可以显式指定要添加的值的编码?

NLS_LANGUAGE AMERICAN 
NLS_TERRITORY AMERICA 
NLS_CURRENCY $ 
NLS_ISO_CURRENCY AMERICA 
NLS_NUMERIC_CHARACTERS ., 
NLS_CHARACTERSET AL32UTF8 
NLS_CALENDAR GREGORIAN 
NLS_DATE_FORMAT DD-MON-RR 
NLS_DATE_LANGUAGE AMERICAN 
NLS_SORT BINARY 
NLS_TIME_FORMAT HH.MI.SSXFF AM 
NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM 
NLS_TIME_TZ_FORMAT HH.MI.SSXFF AM TZR 
NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR 
NLS_DUAL_CURRENCY $ 
NLS_COMP BINARY 
NLS_LENGTH_SEMANTICS BYTE 
NLS_NCHAR_CONV_EXCP FALSE 
NLS_NCHAR_CHARACTERSET AL16UTF16 
NLS_RDBMS_VERSION 11.2.0.2.0 

这是我的NLS参数。事实是,老板严格禁止在数据库级别更改某些内容。对不起,有没有办法做到这一点?

回答

1

不幸的是,你想要做的事情无法实现: 你的字符串'абв'在AL32UTF8字符集中需要6个字节。 您只允许列包含最多3个字节。 您无法为列定义特定的字符集。

每次您向数据库提供特定编码的字符串时,它都会自动将其转换为字符集中正确的表示形式。这是一项功能,您可以在不同的字符集设置中插入(和查询)不同的客户端,但始终可以获得正确的编码。

这导致了一些丑陋的技巧,这在某些客户端(我不知道C#)中是可能的: 向数据库发送一组字符时,您告诉它,该字符串与数据库具有相同的字符集NLS_CHARACTERSET。由于不需要转换,因此通常不检查字符串,只是插入行中。 只要字符串只由同一个客户端(与数据库具有相同的字符集)选择,一切似乎都很好。 但是,无论何时在数据库中使用该字符串(很可能是查询的WHERE部分中的某处),都会出现无法预料的结果。如果任何使用其他编码的客户端尝试访问这些数据,情况也是如此。 这就是为什么我建议而不是来实施这样的黑客行为。

+0

对于.NET,它取决于您在应用程序中使用哪个驱动程序/提供程序。一些从NLS_LANG(例如ODP.NET unmanged驱动程序)继承设置,另一些依赖于当前的Windows语言环境(例如ODP.NET托管驱动程序)以及其他总是使用UTF-16(例如来自Oracle的OraOLEDB)。 –

+1

事实上,不建议这样的破解。无论如何,它不会在你的情况下工作。例如,如果您将字节式的'абв'作为CP866传输,那么这将导致Oracle将立即用占位符(例如'¿')替换UTF-8字符(即非有效字节值)的无效字符。提到的破解可能只适用于数据库字符集覆盖**任何**字节值的情况,例如所有ISO8859-x编码或Windows CPxxxx –