重音字符需要占用一个额外的字符。

3
我遇到了以下问题:
我需要将在表单中输入的数据存储在数据库中。 我验证输入的数据不超过40个字符。
问题是,如果我插入一个包含40个字符但其中一个带有重音符号的文本,那么显然验证不会显示任何错误,但当它将要存储在数据库中时,就会抛出以下异常:
ORA-12899:列"DBUSER"."TABLE"."COLUMN"的值太大(实际值为41,最大值为40)
看起来重音符号在数据库中占据了多个字符。
我想这与编码有关,但我不知道从哪里开始查找。 有什么想法吗?
谢谢!

参数NLS_CHARACTERSET被设置为AL32UTF8。 - Neets
2
UTF-8是Unicode编码。有些有效的Unicode字符需要多个字节来编码。看起来你找到了其中一个。 - DwB
你为什么有一个40个字符的限制? - dan04
1
@DwB:除非您将该列声明为varchar2(40 char)。 - Adam Musch
业务逻辑要求字符串不能超过40个字符。我的错误在于我不知道字符串是如何存储在varchar2类型的字段中的。但感谢大家的评论和答案! - Neets
显示剩余3条评论
2个回答

4

1
NVARCHAR2绝对是正确的选择。当然,像这样切换数据类型并不是一个简单的过程。问题源于设计不良:选择了Unicode字符集,但没有构建支持它的数据模型。现在是指向SO的守护神Joel Spolsky的那篇文章的好时机:http://www.joelonsoftware.com/articles/Unicode.html - APC
就我的经验,过去我采取的方法是预算一定比例的非ASCII字符。如果您正在构建一个处理多种欧洲语言的网站,那么您可能需要允许大约10%的字符带有重音符号(在《世界报》首页文章中,我刚刚测量了3.4%; 10%还有足够的余地)。因此,如果您有一个40个字符的字段,则允许其为44个字节。 - Tom Anderson
1
说实话,考虑到 Oracle 和其他现代数据库存储字符串的方式,我可能会将每个 (n)varchar 列声明为 4000 个字符长,并在应用程序层面进行所有验证。 - Tom Anderson

3
使用CHAR,就像@Adam Musch建议的那样。你真的不想使用NVARCHAR2,或者猜测可能的字节数。
create table my_table1(small_string varchar2(1 byte));
create table my_table2(small_string varchar2(1 char));

insert into my_table1 values('Þ'); --"ORA-12899: value too large for ..."
insert into my_table2 values('Þ'); --works fine

您可以明确地将长度语义设置为BYTE或CHAR,但最可能使用的是默认值BYTE。默认值由NLS_LENGTH_SEMANTICS确定。使用以下查询检查该值:

select * from v$parameter where name = 'nls_length_semantics';

您可以使用以下语句更改默认设置。(虽然您可能会忘记更改此参数,但在DDL中明确使用CHAR更加可靠。)
alter session set nls_length_semantics = char;

该设置不会改变现有对象,您需要使用SQL手动更改表格,例如:

alter table my_table1 modify (small_string varchar2(1 char));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接