12. 公司要上国产数据库,从MySQL迁移到达梦,SQL语法兼容性实测有哪些高频报错?

2026-08-23

前阵子公司响应号召,要把一套核心业务系统从MySQL迁到达梦。老板一句话,底下跑断腿。我心想,都是关系型数据库,能有多大差别?结果真动手迁的时候,脸被打得啪啪响。今天不聊高大上的架构,就聊聊我们在SQL兼容性上踩到的一堆高频报错,给兄弟们提个醒。

第一个坑:空字符串和NULL,它俩不是一回事

MySQL里,''和NULL在排序和聚合的时候差别不大,但在达梦里是严格区分的。我们有个表,性别字段默认是空字符串'',几百万条数据。迁移过去后,查询WHERE gender = ''直接报错或查不出数据。

打比方说,MySQL像个大大咧咧的房东,空字符串和NULL都算“没人住”;达梦则是个精细的管家,必须把“房间是空的”和“压根没分配房间”分得门儿清。这玩意没法批量改,只能逐个排查字段逻辑,非常酸爽。

第二个坑:group by的宽松与严格

MySQL有个“特性”(其实是陋习),select出来的非聚合列可以不在group by里。比如select name, age from t group by name,MySQL能跑,但达梦直接报错“不是GROUP BY表达式”。

这相当于什么?MySQL允许你带个编外人员进会议室,达梦要求每个参会人员都得有正式工牌。所以迁移时,要么把所有非聚合字段都加到group by里,要么改成any_value()函数。我们有个报表SQL,光改这个就折腾了半天。

第三个坑:自增列的“身份证”写法

MySQL里auto_increment用惯了,到达梦得改成IDENTITY(1,1)。这只是语法差异,还好办。最烦人的是,达梦对自增列的操作限制多,比如你想给表插入一条指定ID的数据,在MySQL里随便插,在达梦里就得先显式开启IDENTITY_INSERT,否则报错。

打比方说,MySQL的自增列像发号机,你可以手动插队取号;达梦的则是银行柜台叫号,你想自己喊个VIP号,得先找经理开权限。

第四个坑:LIMIT和字符串拼接的“方言”问题

MySQL分页用LIMIT 10, 20,达梦支持但更推荐LIMIT 20 OFFSET 10,这个还好。真正头疼的是字符串拼接。MySQL里concat('a', 'b')和'a' + 'b'(隐式转换)都行。达梦里,+号是严格的加法运算,遇到'a' + 'b'直接报“不是有效的数字”。

这就像普通话和粤语的差别,字一样,意思完全跑偏。我们有个接口的排序字段,代码里拼了'%' + keyword + '%',迁完直接500。后来全部改成concat函数,记住,达梦用||或者concat(),千万别用+。

第五个坑:改字段类型,比想象中麻烦

MySQL里ALTER TABLE t MODIFY COLUMN age VARCHAR(20),干净利落。达梦里你得用ALTER TABLE t ALTER COLUMN age SET DATA TYPE VARCHAR(20)。不仅语法长,而且当字段有默认值或索引时,经常报“无效的 alter option”。

为了改一个字段长度,我们得先把索引删掉,改完再加回去,前前后后一周时间就耗在这种“体力活”上了。

最后说点心得

如果你也接了这种活,千万别急着直接连生产库。先用数据迁移工具把表结构导过去,跑一遍兼容性分析,达梦的迁移工具会提示有风险的SQL,但别全信,它有时候过于保守,有时候又漏报。

我的血泪建议是:先在测试环境把SQL日志全开,然后把业务流量导进去跑个压测,让报错自己跳出来。我们当时大概整理了200多条需要改的SQL,其中100条都是上面这些坑的变种。

说白了,MySQL到达梦,语法兼容性不是“能不能跑”的问题,而是“愿不愿意帮你圆场”的问题。MySQL太宽松,什么都惯着你;达梦太较真,SQL写得不够规范就给你颜色看。

希望这篇分享能让大家少掉几根头发。如果你们也遇到类似疑难杂症,或者想要一些现成的迁移脚本和踩坑清单,欢迎去 itfangan.com 逛逛,上面有不少同行整理的实战方案,比一个人瞎琢磨有效率多了。