为提高效率,提问时请提供以下信息,问题描述清晰可优先响应。
【DM版本】: 1-1-190-21.04.02-137571-ENT Pack3
【操作系统】:Window2012 Server
【CPU】: X64
【问题描述】*:字段A定义为varchar(1000),但执行select char_length(A) as "字符数"from T,结果却大于1000。详见如下截图:
你好,如果没有特殊需求,禁止开LENGTH_IN_CHAR。
达梦数据库支持varchar类型按字符存储,在某些异构数据库中,如PG或MySQL中,有些数据类型是按字符为单位存储的,这种异构数据库的数据迁移到达梦的时候,如果不注意,可能会有迁移失败的问题,数据库在达梦不能入库。针对此种类型的数据,达梦提供了两种方式来解决:
1.达梦数据库初始化的时候开启参数length_in_char=1,即varchar类型以字符为单位。
2.先将异构数据库的表结构迁移到达梦,注意迁移前修改达梦数据库对应的兼容性参数(COMPATIBLE_MODE),然后修改达梦数据库中的表结构varchar类型为按字符存储,如varchar(10)修改为varchar(10 char)。
第一种方式在达梦数据库初始化的时候可以直接兼容这种按字符存储的数据,但缺点是该length_in_char参数只是表象上的解决该问题,实际是将数据精度扩大为4倍,因此虽然表面上满足了按字符存储的需求,但是实际上是可以存储多个字符的,有悖于表结构设计的初衷,这种情况下为了严格限制数据符合要求只能再到应用中去做限制。
第二种方式则是严格遵循其他异构数据库表结构设计规范的,缺点就是需要批量对表结构做修改,后续有新增的表时也需要注意建表语句的数据类型设计规范。
使用第二种方式修改表结构时,可以使用以下语句生成待执行的修改SQL,然后批量执行即可
SELECT DISTINCT
'ALTER TABLE "'
||A.OWNER
||'"."'
||A.TABLE_NAME
||'" MODIFY "'
||A.COLUMN_NAME
||'" '
||(CASE A.DATA_TYPE WHEN 'CHAR' THEN 'VARCHAR' ELSE A.DATA_TYPE END)
|| '('
||A.DATA_LENGTH
||' CHAR);'
FROM
DBA_TAB_COLS A
JOIN DBA_OBJECTS B
ON
A.TABLE_NAME=B.OBJECT_NAME
WHERE
A.OWNER ='SCHEMA_NAME'
AND B.OBJECT_TYPE='TABLE'
AND
(
A.DATA_TYPE LIKE 'VARCHAR%'
OR A.DATA_TYPE LIKE 'CHAR%'
);
建议重新建库,关闭LENGTH_IN_CHAR,调整表中字符精度
示例:
varchar(10)修改为varchar(10 char)
批量调整方法参考我上条回复
请问是不是开启了LENGTH_IN_CHAR初始化参数,可以使用如下SQL校验是否开启:
select * from v$option where PARA_NAME='LENGTH_IN_CHAR';
返回1表示开启,所有 VARCHAR 类型对象的长度以字符为单位。这种情况下,定义长度并非真正按照字符长度调整,而是将存储长度值按照理论字符长度进行放大。所以会出现实际可插入字符数超过定义长度的情况,这种情况也是允许的。
可以这样算一下,字符集为UTF-8时,varchar(1000)实际长度可以按照4000算,一个汉字占用三个字节,所以大概可以存1333个汉字,字母的话可以存4000个。
gb18030相当于定义的2倍,varchar(1000)实际长度可以按照2000算