阿里云大数据实战记录3:MySQL迁移到ODPS SQL

最近在做一些业务宽表的迁移,因为一个比较老的数仓示例已基本已弃用。该仓库为了快速响应数据需求,采用简单模式,没分开发环境和生产环境,使用的查询语言是MySQL。而迁移的目标仓库是标准模式(开发生产分环境跑),使用的ODPS SQL。

在迁移的过程中,经常遇到的报错问题就是关于数据类型不一致,一段几百行的SQL,报错,调试,定位到问题,修改好,重跑,又报错……改了又改,最终跑通之后,粗算一下时间,足足得有三小时。

这让我深刻感受到MySQL的灵活性和ODPS SQL的“不友好”。但MySQL的灵活究竟是好是坏呢?
如果是拿来入门学习,MySQL真的太友好了,写SQL的时候不用太过于纠结字段的类型,这对于小白来说是福音。
但是熟悉了MySQL之后,还是需要跳出来,去接触一些其他的SQL,比如pgsql或hive SQL,他们的一些规范,可以更好地锻炼个人的一些专业性,至少他们在数据类型的规范上是相当严格的!这可以让自己对数据的类型有更深刻的理解。

说回原来的话题,本次迁移其实是将代码换个地跑,MySQL和阿里云的ODPS SQL(和hive SQL差不多)二者的语法上有一些差异,而且对字段的数据类型的要求也不尽相同,所以修改的地方基本就是语法、数据类型。

语法bug

语法主要就是函数的应用了,如

MySQL ODPS SQL
if case when
ifnull() 多值:coalesce()
二值:nvl()
regexp rlike
right([col_name],x) sunstring(,-x,x)
date_add([col_name],interval xx day) dateadd([col_name],xx,‘dd’)
group_concat([col_name1] separator ‘,’),乱序;
排序:group_concat([col_name1] order by [col_name2] separator ‘,’)
去重:group_concat(distinct [col_name1] separator ‘,’)
去重并排序(排序必须是指定的聚合的字段):group_concat(distinct [col_name1] order by [col_name1] separator ‘,’)
wm_concat(‘,’,[col_name]),默认升序;
去重:wm_concat(distinct ‘,’, [col_name])
排序:wm_concat(‘,’,[col_name1]) within group(order by [col_name2] desc)
去重并排序(排序必须是指定的聚合的字段,并且必须是string类型):
wm_concat(distinct ‘,’,[col_name1]) within group(order by [col_name1] desc)
date_format([col_name],[format])
[format]格式:
yyyy-MM-dd HH:mi:ss(非Hive兼容,使用mm返回月份)
yyyy-MM-dd HH:mm:ss(Hive兼容,使用mi返回null)
注:使用时需要加set odps.sql.hive.compatible=true;(兼容)或set odps.sql.hive.compatible=false;(非兼容),不加set会报错:FAILED: ODPS-0121125:Not Support DatetimeFunc date_format(string, string) yet, please run in hive compatible mode
date_format([col_name],[format])
[format]格式:%Y-%m-%d %H:%i:%s

官方文档有很全的介绍,可以收藏起来备查,感兴趣可以看看:与Hive、MySQL、Oracle内建函数对照表。
注:日期有date、datetime、timestamp等,需要注意日期函数的返回值的数据类型。

使用wm_concat()同时去重和排序可能会出现的错误:

Semantic analysis exception - in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list

该错误可能是order by接的列和聚合的列不是同一个,也可能是数据类型不是string。保证字段相同并且数据类型都是string,基本就不会报这个错。

Semantic analysis exception - All WITHIN GROUP order by must be the same in each SELECT List

这是在同一个select语句中,根据不同的列,使用wm_concat()进行多次去重和排序,这种情况下必须保证所有order by跟的字段都相同。解决方法参考:order by默认升序,无特殊要求,可不指定排序了;一定需要指定排序,拆分为几个select子查询,再合并。

数据类型不匹配

union

数据类型不匹配,如

FAILED: ODPS-xxx:[2,8] Illegal union operation - type mismatch for column 0 of UNION, left is BIGINT while right is STRING

这个会比较隐蔽,因为几百行SQL中有好些union all。于是,注释大法,砍对半跑,快速定位错误位置。找到之后通过cast(xxx as string)对字符类型进行修改。

条件限制(比大小)

如date和datetime比大小,会报错。需要保证date和date或者datetime和datetime比较。数据类型转化可以通过datetime([date])date([datetime])进行转换,或者通过cast([date] as datetime)cast([datetime] as date)进行显示转化。

最后代码终于可以跑起来了,但是一验证,又跨了——数据量少了一半!
于是针对每个union all分别进行统计数据量,一级级向上定位,终于发现了问题所在,问题语法类似where paid_time>'2022-09-01 00:00:00'paid_timedatetime类型),这个语法在MySQL是没有问题的,引擎会帮我们自动将数据类型转化一下,但是在ODPS SQL这二者是不同的数据类型,datetimestring没法比较。这是一个比较隐蔽的数据类型不匹配的问题,虽然代码可以跑了,却没有数据。

你可能感兴趣的:(阿里云大数据,mysql,sql,odps,大数据)