目录
- >> 问题背景:
- >> 阴差阳错:
- >> 问题出现:
- >> 问题排查:
- >> 知识点:
- >> 问题复盘:
- >> 问题拓展:
>> 问题背景:
- Oracle下:从Database1通过DBlink方式抽取数据到Database2;
- Database1:表:Source_Table;Database2:表:Target_Table;字段:Company_Name;
- 字段类型:VARCHAR2(100 CHAR)。
>> 阴差阳错:
- 个人习惯比较喜欢用DBeaver,用不惯PLSQL Developer
- 用DBeaver打开查看Source_Table的表结构时,看到字段Company_Name的字段类型是VARCHAR2(100),导致我建表Target_Table的时候,Company_Name字段类型指定为VARCHAR2(100)了。
- 实际上它在PLSQL Developer打开是VARCHAR2(100 CHAR)
PLSQL Developer查看如下:
DBeaver查看如下:
>> 问题出现:
当我一执行抽取数据任务时候,就看到以下报错了。
数据库报错:ORA-12899: value too large for column "ODS"."Target_Table"."COMPANY_NAME" (actual: 237, maximum: 100)
>> 问题排查:
我此刻还一直以为:Company_Name这个字段的类型,源表与目标表都是Varchar2(100)
“为什么,为什么源表也是100,就没有报错,到了目标表这里就报错了?为什么?”
- 去到源表,查了这个字段最大的长度是83而已啊。
- 隐隐约约察觉到,会不会是那些什么字符、字节的差异啊,把这个83的字段数据拉出来看一下
- 单独复制粘贴到文本编辑器看,确实是83个字符,可以理解成我们平时写作文说的83个字了吧,而不是字节什么乱七八糟的。
- 最后的最后,突然发现源表在PLSQL Developer中,Company_Name字段类型是:VARCHAR2(100 CHAR),而我一直是用:VARCHAR2(100),所以改了一下类型后再去复现问题,发现问题不存在了。好的,到了这里,问题原因找到了,就是VARCHAR2(100)和VARCHAR2(100 CHAR)两个类型差异导致的报错。
>> 知识点:
VARCHAR2(100)
就相当于VARCHAR2(100 byte),表示最大字节数是100,该字段最多能容纳100个字节,强调空间大小。由于我们描述的是字节,因此,保存汉字等字符时,就要小心了。如果你的数据库用的是GBK编码,那么一个汉字将占用2个字节,最多能存50个汉字,如果你的数据库用的是UTF8编码,那么一个汉字将占用3个字节,最多能存33个汉字。
VARCHAR2(100 CHAR)
VARCHAR2(CHAR):表示最大字符数是100,该字段最多能容纳100个字符,强调个数。假设我们写成VARCHAR2(100 CHAR),那么无论是数字、字母、汉字,都看成一个字符,最多写100个,当然,汉字越多,占用的空间越大,同样遵循上边的数据库编码原则。例如:存入一个汉字,底层占2或3个字节,存入一个字母,占1个字节。
小结:
Oracle,有两种比较常用的类型:VARCHAR2(byte)、VARCHAR2(char)
无论是VARCHAR2(byte)还是VARCHAR2(char),最大字节数都是4000。
>> 问题复盘:
- 确认我们数据库的编码是UTF8,也就是说:如果我的字段类型是:VARCHAR2(100),那么实际上仅仅可以存33个汉字左右,一个汉字占3个字节(UTF8编码下)。
- 而源表的Company_Name字段类型可是VARCHAR2(100 CHAR),也就是它无论是数字、字母、汉字,都看成一个字符,最多写100个。所以才一开始报错:数据库报错:ORA-12899: value too large for column
-- 查询数据库的编码
SELECT VALUE
FROM NLS_DATABASE_PARAMETERS
WHERE PARAMETER = 'NLS_CHARACTERSET'
>> 问题拓展:
- 实际应用中,很可能会出现这种写法:VARCHAR2(1400 CHAR),我们主观的认为,这个字段最长不能超过1400个字符,这意味着我们可能会存入1399个字符,貌似很正确的样子。
- 但是,如果这1399个字符都是汉字,字符长度并没有超过1400,看起来一切正常,但实际上我们损失了一部分数据,为什么?
- 因为1399个汉字,按UTF8编码来说(99%的项目都是UTF8编码),需要占用1399*3=4197个字节,而文章开篇就说,无论是什么char,最大长度就是4000字节,一个也不能多,因此多出来的197个字节,都会抹去,而整个过程中,无任何错误提示。
--对于UTF8编码的数据库而言,安全的写法为:
varchar2(1333 char)--对于GBK编码的数据库而言,安全的写法为:
varchar2(2000 char)