前言
写这篇文章的目的就是想浅浅记录下日常工作中的小成就
背景
因为我们公司的数据平台在抽数据的时候无法自动生成ODS层hive格式的建表语句,而业务库的一些表字段又非常多,手动+excel修改耗时耗力,于是想通过一个Python脚本自动将mysql格式的建表语句转换成hive格式的。
转换前:
CREATE TABLE `ai_warning_info` (
`id` varchar(40) NOT NULL COMMENT '主键',
`community_id` varchar(40) NOT NULL DEFAULT '' COMMENT '园区id',
`ai_warning_config_id` int(11) NOT NULL COMMENT '预警信息配置表主键id',
`warning_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '预警状态(1:待处理;2:已恢复;3:已处理(后台预警管理操作 直接处理/生成工单,则这条预警信息变成已处理))',
`warning_content` varchar(500) NOT NULL DEFAULT '' COMMENT '预警内容',
`warning_rank` tinyint(4) NOT NULL DEFAULT '0' COMMENT '预警级别(1:严重;2:重要;3:一般)',
`warning_time` datetime DEFAULT NULL COMMENT '预警时间',
`intime` datetime DEFAULT NULL COMMENT '写入时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) NOT NULL DEFAULT '' COMMENT '说明',
`operate_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '预警处理方式1:直接处理;2:生成工单',
`operate_user_id` varchar(45) NOT NULL DEFAULT '' COMMENT '预警信息处理人id',
`operate_user_name` varchar(45) NOT NULL DEFAULT '' COMMENT '预警信息处理人name',
`operate_time` datetime DEFAULT NULL COMMENT '预警信息处理时间',
`order_id` varchar(40) DEFAULT '' COMMENT '工单id',
`order_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '工单状态 0缺省 1待接收 2处理中 3已处理 4已完成 5已关闭 6待处理',
`recovery_time` datetime DEFAULT NULL COMMENT '恢复时间',
`warning_trigger_id` varchar(45) NOT NULL DEFAULT '' COMMENT '触发预警事件的记录id',
`warning_type` tinyint(4) NOT NULL COMMENT '预警事件类型(1离园预警 2车辆违停 3消防通道占用)',
`work_order_identity` int(10) DEFAULT NULL COMMENT '新旧工单标识字段 1:老工单,2:新工单',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `id_UNIQUE` (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='ai预警信息';
转换后:
CREATE TABLE IF NOT EXISTS ods_wspace_ai_warning_info_df (
id STRING COMMENT '主键'
,community_id STRING COMMENT ' COMMENT '
,ai_warning_config_id STRING COMMENT '预警信息配置表主键id'
,warning_status STRING COMMENT '预警状态(1:待处理;2:已恢复;3:已处理(后台预警管理操作 直接处理/生成工单,则这条预警信息变成已处理))'
,warning_content STRING COMMENT ' COMMENT '
,warning_rank STRING COMMENT '预警级别(1:严重;2:重要;3:一般)'
,warning_time STRING COMMENT '预警时间'
,intime STRING COMMENT '写入时间'
,update_time STRING COMMENT '更新时间'
,remark STRING COMMENT ' COMMENT '
,operate_type STRING COMMENT '预警处理方式1:直接处理;2:生成工单'
,operate_user_id STRING COMMENT ' COMMENT '
,operate_user_name STRING COMMENT ' COMMENT '
,operate_time STRING COMMENT '预警信息处理时间'
,order_id STRING COMMENT ' COMMENT '
,order_status STRING COMMENT '工单状态 0缺省 1待接收 2处理中 3已处理 4已完成 5已关闭 6待处理'
,recovery_time STRING COMMENT '恢复时间'
,warning_trigger_id STRING COMMENT ' COMMENT '
,warning_type STRING COMMENT '预警事件类型(1离园预警 2车辆违停 3消防通道占用)'
,work_order_identity STRING COMMENT '新旧工单标识字段 1:老工单,2:新工单'
)
COMMENT 'ai预警信息'
PARTITIONED BY ( ds BIGINT )
STORED AS PARQUET;"
转换脚本是我让我小姐妹写的,她起初发给我的是这样的:
import os
import re
import traceback
import pandas as pd
pattern = r"[`']([^`']+)[`']"
tradition_ = 'COMMENT'
common_part = ' STRING COMMENT '
def modify_row(row):
sql_row = row[0]
if 'CREATE TABLE' in sql_row:
return row
if 'COMMENT=' in sql_row:
comment = sql_row.split('COMMENT=')[-1].replace(';', '').replace(' ', '')
cut_sql = ')COMMENT ' + comment + ' PARTITIONED BY (As BIGINT) STORED AS PARQUET;'
row[0] = cut_sql
return row
cut_result = re.findall(pattern, sql_row)
if len(cut_result) > 1 and tradition_ in sql_row:
cut_sql = cut_result[0] + common_part + f"'{cut_result[-1]}'" + ','
row[0] = cut_sql
return row
current_dir = os.getcwd()
to_dir = os.path.join(current_dir, "results_dir")
print('current_dir:', current_dir)
print('results_dir:', to_dir)
if not os.path.exists(to_dir):
os.mkdir(to_dir)
try:
for file in os.listdir(current_dir):
if file.endswith(".xlsx") or file.endswith(".xls"):
file_path = os.path.join(current_dir, file)
to_file_path = os.path.join(to_dir, file)
df = pd.read_excel(file_path)
df.apply(modify_row, axis=1)
df.to_csv(to_file_path, index=False)
except:
print(traceback.format_exc())
还给我解释了一下,真的太有爱了,啊哈哈哈哈

不过这个转换完是下面这样:
CREATE TABLE `ai_warning_info` (
id STRING COMMENT '主键',
community_id STRING COMMENT ' COMMENT ',
ai_warning_config_id STRING COMMENT '预警信息配置表主键id',
warning_status STRING COMMENT '预警状态(1:待处理;2:已恢复;3:已处理(后台预警管理操作 直接处理/生成工单,则这条预警信息变成已处理))',
warning_content STRING COMMENT ' COMMENT ',
warning_rank STRING COMMENT '预警级别(1:严重;2:重要;3:一般)',
warning_time STRING COMMENT '预警时间',
intime STRING COMMENT '写入时间',
update_time STRING COMMENT '更新时间',
remark STRING COMMENT ' COMMENT ',
operate_type STRING COMMENT '预警处理方式1:直接处理;2:生成工单',
operate_user_id STRING COMMENT ' COMMENT ',
operate_user_name STRING COMMENT ' COMMENT ',
operate_time STRING COMMENT '预警信息处理时间',
order_id STRING COMMENT ' COMMENT ',
order_status STRING COMMENT '工单状态 0缺省 1待接收 2处理中 3已处理 4已完成 5已关闭 6待处理',
recovery_time STRING COMMENT '恢复时间',
warning_trigger_id STRING COMMENT ' COMMENT ',
warning_type STRING COMMENT '预警事件类型(1离园预警 2车辆违停 3消防通道占用)',
work_order_identity STRING COMMENT '新旧工单标识字段 1:老工单,2:新工单',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `id_UNIQUE` (`id`) USING BTREE
)COMMENT 'ai预警信息' PARTITIONED BY (As BIGINT) STORED AS PARQUET;
然而。。。。

行吧 对齐看着也比较舒服
于是和姐妹吐槽,我在手动对齐

最后实在受不了了,改了姐妹的代码
对齐大概思路就是设置一个最大值减去字段长度再乘以空格,就可以对齐啦
顺便按照自己的需求又照猫画虎的改了下
import os
import re
import traceback
import pandas as pd
pattern = r"[`']([^`']+)[`']"
tradition_ = 'COMMENT'
common_part = ' STRING COMMENT '
#定义一个空字符
space=' '
def modify_row(row):
sql_row = row[0]
if 'CREATE TABLE' in sql_row:
table = sql_row.split('`')[1]
# 顺便把ods规范表名也拼好
cut_sql = 'CREATE TABLE IF NOT EXISTS ' + 'ods_wspace_'+table.replace(' ','') +'_df ('
row[0] = cut_sql
return row
# 去掉不符合要求的语句行
if 'USING BTREE' in sql_row:
cut_sql =' '
row[0] = cut_sql
return row
# 因为公司同步都要求string 就方便很多 直接按字符串类型拼
if 'COMMENT=' in sql_row:
comment = sql_row.split('COMMENT=')[-1].replace(';', '').replace(' ', '')
cut_sql = ')'+'\n'+'COMMENT ' + comment +'\n'+ 'PARTITIONED BY ( ds BIGINT )'+'\n'+'STORED AS PARQUET;'
row[0] = cut_sql
return row
cut_result = re.findall(pattern, sql_row)
# 通过字段长度 对齐语句
cut_len=len(cut_result[0])
# print('cut_len:',cut_len)
if len(cut_result) > 1 and tradition_ in sql_row:
cut_sql = 5*space+','+cut_result[0] +(30-cut_len)*space+common_part +space+ f"'{cut_result[-1]}'"
row[0] = cut_sql
return row
current_dir = os.getcwd()
to_dir = os.path.join(current_dir, "results_dir")
print('current_dir:', current_dir)
print('results_dir:', to_dir)
if not os.path.exists(to_dir):
os.mkdir(to_dir)
try:
for file in os.listdir(current_dir):
if file.endswith(".xlsx") or file.endswith(".xls"):
file_path = os.path.join(current_dir, file)
to_file_path = os.path.join(to_dir, file)
df = pd.read_excel(file_path)
df.apply(modify_row, axis=1)
df.to_csv(to_file_path, index=False)
except:
print(traceback.format_exc())
姐妹说用pandas库 可能有bug 但她迟迟不帮我优化 反正我们一致认同能实现功能的代码就是好代码 哈哈哈哈哈 坐等她再帮我换个库写 反正 这段时间不用手敲建表语句了 开心开心
为啥说用一行代码实现呢,因为

命令行。。。 被骗了 我是标题党
后记
时隔一年没有跟新了 确实平常很躺平 工作中除了sql就是sql 很少学新的内容 就没有产出了 希望之后能多多更新文章吧 这篇就是一个好的开端
by the way 今天是我入职满一年 下班下班 出去嗨喽
1267

被折叠的 条评论
为什么被折叠?



