往表里插一条中文,报 ORA-12899: value too large for column。字段明明写的是 VARCHAR2(20),输入的字数也没超,问题出在长度按字节算,一个汉字在 UTF-8 库里要吃 3 个字节。

先确认字段按字节还是按字符

查数据字典能看到长度语义:

select column_name, data_type, data_length, char_length from user_tab_columns where table_name = 'T_USER';

char_length 有值是按字符,为空是按字节。也可以直接翻建表语句,VARCHAR2(20 CHAR) 带 CHAR 关键字的才按字符算。

SUBSTR 和 SUBSTRB 差在哪儿

SUBSTR 按字符截,SUBSTRB 按字节截。后者遇到中文容易把字节切断,取回来是乱码或者问号。日常截字符串用 SUBSTR:

select substr(name, 1, 10) from t_user;

要往按字节限长的字段里塞,只能循环减长度试,或者干脆把字段改成字符语义,省掉这层换算。

入库前统一截一刀

导外部数据时长度不可控,写库前先截断,比等报错再回滚划算:

insert into t_log (title) select substr(trim(title), 1, 50) from t_log_tmp;

空值和全空格要先过滤,否则截出来是空串,业务层还得再判一次。字符集也要对齐,源库是 GBK、目标库是 UTF-8 时,字节数会整体变长。

查询结果看着被截断是另一回事

数据没丢,是 SQL*Plus 或者客户端列宽不够,行尾直接省略了。调一调 linesize,或者把列宽拖大再看。PL/SQL Developer 里右键列头调宽度就行,别误判成存储层坏了。

另外,字符串拼接超长也会报截断,比如两个 VARCHAR2(100) 拼起来塞进 VARCHAR2(150),这种在 SQL 里用 length 先算一遍更稳。

判断:新建表统一写 VARCHAR2(n CHAR),长度按字符心里有数;存量表按字节的,插入前用 SUBSTR 限长,别靠报错发现问题。