一、前言
在阿里云 dataworks 开发数据表单的时候,可能你也会有过这样的经历:数据表的字段和要插入的数据类型不一致。
最近,在数仓处理一个数据表就遇到了这个问题。该表单记录了很多历史的数据,包含记录的状态、更新的版本等,在大多数业务中,只需要看用户维度的一条数据,根据状态先做优先级判断,再根据版本进行排序,由近到远;但是也需要保留相关历史数据,以便其他业务使用。
每次读表都需要做一层去重动作,通过窗口函数,按状态和版本进行相关排序,再进行取值。整个过程较为繁琐且较为低效,而且查询的次数多于数仓跑调度的次数,比较浪费资源,于是打算将其放到数仓中进行计算,而在查询时直接使用。
二、新增字段
其实整个需求很简单,就是在开发表中新增一个字段,然后发布到开发环境和生产环境,再在代码中加入计算逻辑,提交、发布即可。
但是一开始误判了窗口函数返回值的数据类型,导致新增的字段类型和插入数据的数据类型不匹配,从而报错,即设置的数据类型是INT
,而窗口函数返回的数据类型是BIGINT
。
于是要填自己挖的坑......
三、修正数据类型
3.1 修改字段的数据类型
尝试通过修改表单相关字段的数据类型:
sql
-- 修改开发环境表 table_name.col_1 的数据类型为 bigint
alter table xxx_dev.table_name change col_1 col_1 bigint;
-- 修改生产环境表 table_name.col_1 的数据类型为 bigint
alter table xxx.table_name change col_1 col_1 bigint;
结果报错:
FAILED: Catalog Service Failed, ErrorCode: 152, Error Message: ODPS-0110061: Failed to run ddltask-ODPS-0110061: Failed to run ddltask - Schema evolution DDLs is not enabled in project:xxx_dev
通过错误提示中的关键字进行搜索,查询到阿里云提供的解析和解决方案,如下:
相关链接:https://help.aliyun.com/zh/maxcompute/user-guide/odps-0110061
错误原因是当前项目默认不允许表结构变更 ,如新增struct类型的子列、删除列、修改列顺序和更改列数据类型。
解决方案:加上set project odps.schema.evolution.enable=true;
命令提交。
不过加上命令之后,产生了另外的错误:没有相关权限进行项目安全操作。
FAILED: ODPS-0420095: Access Denied - Authorization Failed [4003], You have NO privilege to do the PROJECT SECURITY OPERATION for {acs:odps:*:projects/xxx_dev/authorization/properties/odps.schema.evolution.enable}. Context ID:94737bec-78d6-4a00-xxxx. --->Tips: Pricipal:xxxx@qq.com:xxxxx;
3.2 删表重建
修改字段的数据类型行不通,根据相关提示也了解到不能删除列,这都属于安全操作。那就只好删表重建一下。
删表需要对开发环境和生产环境的表单进行操作,而建表可以只建开发环境表,提交发布后自动生成生产环境表,当然,也可以手动创建一下。
sql
-- 删表
drop table if exists xxx_dev.table_name;
drop table if exists xxx.table_name;
-- 建表
create table if not exists xxx_dev.table_name(xx bigint comment'');
create table if not exists xxx.table_name(xx bigint comment'');
其他方案:
如果窗口函数的排序数值可控,能通过 32 位有符号的整型进行覆盖,即取值范围:-2^31~2^31-1,也可以通过cast
修改窗口函数返回的数据类型,示例如下:
sql
cast(row_number()over() as int) as "row_num"
三、总结
最终的方案更准确的说法是删表重建,以实现"修改字段数据类型"的目的,不过中间绕了些弯子。
如果只是在开发环境中处理,还是会比较方便,对开发表进行删表重建(drop + create
),使得数据表的数据类型和要插入的数据保持一致;或者修改插入数据的数据类型(cast
),使得插入数据的数据类型和已创建数据表的数据一致;或直接修改数据表的数据类型(Alter
),这个方案需要项目安全操作的权限。
但是如果是发布到了生产环境,便会更加麻烦,除了以上可供选择的方法需要进行两次操作外,还涉及到表单的使用权限问题,所以一般建议非必要不删表!
往期回顾: