写在前面
之前的项目涉及到了旧项目数据库从MySQL迁移至达梦数据库。
达梦实际上和MySQL相比,更类似于Oracle数据,从Oracle迁移过去则问题相对少一些。
DM8官方文档中是支持开启MySQL兼容模式的:
在配置文件dm.ini中找到COMPATIBLE_MODE
参数修改为4
达梦官方的文档也在更新各种迁移中可能遇到的问题,笔者写下此篇文章是,该文档比当初笔者做项目迁移时丰富了很多,基本可以解决大多数问题。
https://eco.dameng.com/document/dm/zh-cn/faq/faq-mysql-dm8-migrate.html
group by
MySQL在未开启严格模式下,允许group by模式下可以允许查询中group by 子句中不包含所有查询列,而达梦数据库默认是不可以的,如果之前的SQL语句写的不是很规范的话,这里会带来很多修改工作量。
达梦数据库在开启MySQL兼容模式后可以达到同样效果
关于大小写敏感与否的坑
数据库大小写敏感是一个影响比较大的一个坑,笔者的项目再前期对此问题认识不足,导致后续迁移改造过程中问题不断。(╯‵□′)╯︵┻━┻
如果旧数据库的库表与字段名不规范的话,会导致很多情况下无法正常的查询和获取结果列。
数据库大小写敏感后,使用小写且未用双引号括起的查询语句,会被数据库自动转为大写,如果库中表名字段名为小写时,无法完成查询,会提示找不到对象;
当数据库表与字段名为大写时,可以完成查询,但是返回的数据字段名均为大写,
如果使用map接收返回数据并在后续代码中使用get(字段名)获取时,则会无法获取到,产生错误;
在使用MyBait-plus的情况下,某些关键字被加上双引号进行查询,会导致达梦报错;
达梦的官方文档中也提到此问题:
https://eco.dameng.com/document/dm/zh-cn/faq/faq-mysql-dm8-migrate.html#快速设置使得在 mybatis 下对象不用添加双引号
函数相关
部分MySQL常用函数在达梦数据库中缺失或与达梦的函数不是很一致。
下面是我整理的在迁移过程中遇到的
FIND_IN_SET
达梦内置函数没有mysql的find_in_set()函数,但是可以通过自定义函数实现,也是达梦官方推荐的结局方案
自定义一个 FIND_IN_SET 函数
CREATE OR REPLACE FUNCTION FIND_IN_SET
(
piv_str1 varchar2,
piv_str2 varchar2,
p_sep varchar2 := ',')
RETURN NUMBER
IS
l_idx number:=0; -- 用于计算piv_str2中分隔符的位置
str varchar2(500); -- 根据分隔符截取的子字符串
piv_str varchar2(500) := piv_str2; -- 将piv_str2赋值给piv_str
res number :=0; -- 返回结果
loopIndex number :=0;
BEGIN
-- 如果piv_str中没有分割符,直接判断piv_str1和piv_str是否相等,相等 res=1
IF instr(piv_str, p_sep, 1) = 0 THEN
IF piv_str = piv_str1 THEN
res := 1;
END IF;
ELSE
-- 循环按分隔符截取piv_str
LOOP
l_idx := instr(piv_str, p_sep);
loopIndex:=loopIndex+1;
-- 当piv_str中还有分隔符时
IF l_idx > 0 THEN
-- 截取第一个分隔符前的字段str
str:= substr(piv_str, 1, l_idx-1);
-- 判断 str 和piv_str1 是否相等,相等 res=1 并结束循环判断
IF str = piv_str1 THEN
res:= loopIndex;
EXIT;
END IF;
piv_str := substr(piv_str, l_idx+length(p_sep));
ELSE
-- 当截取后的piv_str 中不存在分割符时,判断piv_str和piv_str1是否相等,相等 res=1
IF piv_str = piv_str1 THEN
res:= loopIndex;
END IF;
-- 无论最后是否相等,都跳出循环
EXIT;
END IF;
END LOOP;
-- 结束循环
END IF;
-- 返回res
RETURN res;
END FIND_IN_SET;
GROUP_CONCAT
wm_concat()
LISTAGG (exp1, spr)WITHIN GROUP(<ORDERBY 项>)
原MySQL:
GROUP_CONCAT(b.opt ORDER BY q.order_number ASC)
新:
LISTAGG(b.opt) WITHIN GROUP (ORDER BY q.order_number ASC) AS opt
如果在GROUP_CONCAT()函数中存在distinct操作的话,需要重新改写SQL语句提前去重 或者使用wm_concat()
concat_ws (双引号分隔符"-")
达梦不能用双引号括起分隔符,会被认为是库表
原MySQL:
CONCAT_WS("-",j.starting_city,j.round_route,j.return_city)
新:
CONCAT_WS('-',j.starting_city,j.round_route,j.return_city)
date_add
dateadd(day,a2.leave_days + 30,a2.sjcfTime) 单位,n,date
原MySQL:
date_add(a2.sjcfTime, interval a2.leave_days+30 day)
新:
dateadd(day,a2.leave_days + 30,a2.sjcfTime)
拼音排序
可以使用 NLSSORT 函数
实现此功能,NLSSORT 支持以拼音、笔画、部首排序,示例如下:
拼音:SELECT * FROM PEOPLE ORDER BY NLSSORT(name,'NLS_SORT = SCHINESE_PINYIN_M');
笔划:SELECT * FROM PEOPLE ORDER BY NLSSORT(name,'NLS_SORT = SCHINESE_STROKE_M');
部首:SELECT * FROM PEOPLE ORDER BY NLSSORT(name,'NLS_SORT = SCHINESE_RADICAL_M');
last_insert_id()
可以查询自增列当前值、种子和增量等信息:
SELECT IDENT_CURRENT(‘SYSDBA.IDENT_TABLE’);
SELECT IDENT_SEED(‘SYSDBA.IDENT_TABLE’);
SELECT IDENT_INCR(‘SYSDBA.IDENT_TABLE’);
参考《DM8系统管理员手册》9.6.2 章节:查看自增列信息(手册在DM安装目录下的doc目录下)
now()
MySQL中now()查询当前时间
达梦中为CURRENT_DATE()返回当前日期
CURTIME(n) CURRENT_TIME(n)
SELECT CURDATE();
SELECT CURRENT_TIME()
DATEDIFF()
返回时间间隔DATEDIFF()
mysql:
datediff(now(),date_add(day,a.stay_days + 30,a.start_time))
dm:
DATEDIFF(datepart,date1,date2)
datediff(day,dateadd(day,a.stay_days + 30,a.start_time),CURRENT_DATE())
datepart取值:year
month
day
hour
minute
second
等
datediff日期计算顺序与mysql相反!!为date2-date1!
DATE_FORMAT()
达梦数据库中,使用'%Y年%m月'去格式化日期的时候,会报错
mysql:
DATE_FORMAT(a.last_time,'%Y年%m月')
dm:
CONCAT_WS('',DATE_FORMAT( a.last_time, '%Y' ) ,'年' , DATE_FORMAT( a.last_time, '%m' ) , '月' )
date_part(a.start_time, 'yyyy') || '年' || date_part(a.start_time, 'mm') || '月' || date_part(a.start_time, 'dd') || '日'
银河麒麟系统上,DATE_FORMAT(a.last_time,'%Y-%m-%d')会导致格式化后的日期附带有‘~’号
要改为使用to_char()函数
CHAR类型字段问题
最好在迁移的时候将char类型直接映射为varchar类型