用字符指定:VARCHAR2(10 char)。这将支持最多 10 字符
的数据,可能是多达 40 字节的信息。
使 用 UTF8 之 类 的 多 字 节 字 符 集 时 , 建 议 你 在
VARCHAR2/CHAR 定义中使用 CHAR 修饰符,也就是说,使用
VARCHAR2(80 CHAR),而不是 VARCHAR2(80),因为你的本意很可
能是定义一个实际上能存储 80 字符数据的列。还可以使用会话参数
或系统参数 NLS_LENGTH_SEMANTICS 来修改默认行为,即把默
认设置 BYTE 改为 CHAR。我不建议在系统级修改这个设置,而应
该 只 是在你的数据库模式 安 装 脚 本 中 把 这 个 设 置作 为 ALTER
SESSION 设置的一部分。只要应用需要数据库有某组特定的 NLS 设
置,这必然是一个“不友好“的应用。一般来讲,这种应用无法与其
他不要求这些设置(而依赖于默认设置)的应用一同安装到数据库
上。
还要记住重要的一点:VARCHAR2 中存储的字节数上界是
4,000。不过,即使你指定了 VARCHAR2(4000 CHAR),可能并不能
在这个字段中放下 4,000 个字符。实际上,采用你选择的字符集时如
果所有字符都要用 4 个字节来表示,那么这个字段中就只能放下
1000 字符!
下面这个小例子展示了 BYTE 和 CHAR 之间的区别,并显示
出上界的作用。我们将创建一个包括 3 列的表,前两列的长度分别
是 1 字节和 1 字符,最后一列是 4,000 字符。需要说明,这个测试在
一个多字节字符集数据库上完成,在此使用了字符集 AL32UTF8,
这个字符集支持最新版本的 Unicode 标准,采用一种变长方式对每
个字符使用 1-4 个字节进行编码:
ops$tkyte@O10GUTF> select *
2 from nls_database_parameters
3 where parameter = 'NLS_CHARACTERSET';
PARAMETER VALUE
------------------------------ --------------------
NLS_CHARACTERSET AL32UTF8
ops$tkyte@O10GUTF> create table t
2 ( a varchar2(1),
3 b varchar2(1 char),
4
c varchar2(4000 char)
5 )
6 /
Table created.
现在,如果想在这个表中插入一个 UTF 字符,这个字符长度
为 2 个字节,可以观察到以下结果:
ops$tkyte@O10GUTF> insert into t (a) values (unistr('\00d6'));
insert into t (a) values (unistr('\00d6'))
*
ERROR at line 1:
ORA-12899: value too large for column "OPS$TKYTE"."T"."A"
(actual: 2, maximum: 1)
这个例子展示了两点:
VARCHAR2(1)的单位是字节,而不是字符。这里确实只有一
个 Unicode 字符,但是它在一个字节中放不下。
将应用从单字节定宽字符集移植到一个多字节字符集时,可能
会发现原来在字段中能放下的文本现在却无法放下。
第二点的原因是,在一个单字节字符集中,包含 20 个字符的
字符串长度就是 20 字节,完全可以在一个 VARCHAR2(20)中放下。
不过,在一个多字节字符集中,20 个字符的字符串长度可以到达 80
字节(如果每个字符用 4 个字节表示),这样一来,20 个 Unicode 字
符很可能无法在 20 个字节中放下。你可能会考虑将 DDL 修改为
VARCHAR2(20 CHAR),或者在运行 DDL 创建表时使用前面提到的
NLS_LENGTH_SEMANTICS 会话参数。
如果字段原本就是要包含一个字符,在这个字段中插入一个字
符时,可以观察到以下结果:
ops$tkyte@O10GUTF> insert into t (b) values (unistr('\00d6'));
12.row created.
ops$tkyte@O10GUTF> select length(b), lengthb(b), dump(b)
dump from t;
LENGTH(B) LENGTHB(B) DUMP
---------- ---------- --------------------
1 2 Typ=1 Len=2: 195,150
这个 INSERT 成功了,而且可以看到,所插入数据的长度
(LENGTH)就是一个字符,所有字符串函数都以字符为单位工作。
这个字段的长度是一个字符,但是 LENGTHB 函数(字节长度)显
示这个字段占用了 2 字节的存储空间,另外 DUMP 函数显示了这些
字节到底是什么。这个例子展示了人们使用多字节字符集时遇到的
一个相当常见的问题,即 VARCHAR2(N)并不一定存储 N 个字符,
而只是存储 N 个字节。
人们经常遇到的另一个问题是:VARCHAR2 的最大字节长度
为 4,000,而 CHAR 的最大字节长度为 2,000。
ops$tkyte@O10GUTF> declare
2
l_data varchar2(4000 char);
3
l_ch varchar2(12.char) := unistr( '\00d6' );
4 begin
5
l_data := rpad( l_ch, 4000, l_ch );
6 insert into t ( c ) values ( l_data );
7 end;
8 /
declare
*
ERROR at line 1:
ORA-01461: can bind a LONG value only for insert into a LONG
column
ORA-06512: at line 6
在此显示出,一个 4,000 字符的字符串实际上长度为 8,000 字
节,这样一个字符串无法永久地存储在一个 VARCHAR2(4000 CHAR)
字段中。这个字符串能放在 PL/SQL 变量中,因为在 PL/SQL 中
VARCHAR2 最大可以到达 32KB。不过,存储在表中时,VARCHAR2