最近在做一些业务宽表的迁移,因为一个比较老的数仓示例已基本已弃用。该仓库为了快速响应数据需求,采用简单模式,没分开发环境和生产环境,使用的查询语言是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_time
是datetime
类型),这个语法在MySQL是没有问题的,引擎会帮我们自动将数据类型转化一下,但是在ODPS SQL这二者是不同的数据类型,datetime
和string
没法比较。这是一个比较隐蔽的数据类型不匹配的问题,虽然代码可以跑了,却没有数据。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/66939.html