import pandas as pd import sqlalchemy from sqlalchemy import create_engine import configparser import os from urllib.parse import quote_plus from datetime import datetime def fix_date(date_str): try: # 处理只有年月的情况(如"2018-07") if isinstance(date_str, str) and len(date_str) == 7 and date_str[4] == '-': return datetime.strptime(date_str + '-01', '%Y-%m-%d') return date_str except: return None # 对于无法解析的日期返回NULL def get_db_connection_string(config, section): """从配置文件中构建数据库连接字符串""" return f"mysql+pymysql://{config[section]['user']}:{quote_plus(config[section]['password'])}@" \ f"{config[section]['host']}:{config[section]['port']}/{config[section]['database']}" def transform_and_load_ma_type(config_file_path): """ 从源数据库提取ma_type数据,转换后加载到目标数据库ma_type :param config_file_path: 配置文件路径 """ # 读取配置文件 if not os.path.exists(config_file_path): raise FileNotFoundError(f"配置文件不存在: {config_file_path}") config = configparser.ConfigParser() config.read(config_file_path) try: # 获取数据库连接 source_conn_str = get_db_connection_string(config, 'source_db') target_conn_str = get_db_connection_string(config, 'target_db') source_engine = create_engine(source_conn_str) target_engine = create_engine(target_conn_str) # 从源表读取数据(过滤COMPANY_ID=1且IS_ACTIVE=1的记录) print("正在从源表ma_type读取数据...") source_query = """ SELECT ID, \ PARENT_ID, \ NAME, \ LEVEL, \ UNIT, \ NUM, \ nullif(BUY_PRICE,0) as BUY_PRICE, \ nullif(LEASE_PRICE,0) as LEASE_PRICE, \ IS_COUNT, \ RATED_LOAD, \ TEST_LOAD, \ HOLDING_TIME, \ manage_type, nullif(IS_TEST,0) as IS_TEST, nullif(TIME,0) as TIME FROM ma_type WHERE COMPANY_ID = 1 AND IS_ACTIVE = 1 \ """ source_df = pd.read_sql(source_query, source_engine) if source_df.empty: print("没有符合条件的数据需要转换") return print(f"读取到{len(source_df)}条待转换数据") # 数据转换(直接字段复制) print("正在进行数据转换...") target_df = pd.DataFrame() # 字段映射(源字段 → 目标字段) field_mapping = { 'ID': 'type_id', 'PARENT_ID': 'parent_id', 'NAME': 'type_name', 'LEVEL': 'level', 'UNIT': 'unit_name', 'NUM': 'storage_num', 'BUY_PRICE': 'buy_price', 'LEASE_PRICE': 'lease_price', 'IS_COUNT': 'manage_type', 'RATED_LOAD': 'rated_load', 'TEST_LOAD': 'test_load', 'HOLDING_TIME': 'holding_time', 'manage_type': 'is_enter', 'IS_TEST': 'is_test', 'TIME': 'create_time' } for source_field, target_field in field_mapping.items(): target_df[target_field] = source_df[source_field] # 应用日期修正 target_df['create_time'] = source_df['TIME'].apply(fix_date) # 写入目标表 print("正在写入目标表ma_type...") target_df.to_sql( 'ma_type', target_engine, if_exists='append', index=False, dtype={ 'type_id': sqlalchemy.types.INTEGER(), 'parent_id': sqlalchemy.types.INTEGER(), 'type_name': sqlalchemy.types.VARCHAR(length=100), 'level': sqlalchemy.types.SmallInteger(), 'unit_name': sqlalchemy.types.VARCHAR(length=20), 'storage_num': sqlalchemy.types.VARCHAR(length=50), 'buy_price': sqlalchemy.types.DECIMAL(10, 2), 'lease_price': sqlalchemy.types.DECIMAL(10, 2), 'manage_type': sqlalchemy.types.SmallInteger(), 'rated_load': sqlalchemy.types.DECIMAL(10, 2), 'test_load': sqlalchemy.types.DECIMAL(10, 2), 'holding_time': sqlalchemy.types.INTEGER(), 'is_enter': sqlalchemy.types.SmallInteger(), 'is_test': sqlalchemy.types.SmallInteger(), 'create_time': sqlalchemy.types.DateTime() } ) print(f"成功写入{len(target_df)}条数据") except Exception as e: print(f"处理过程中发生错误: {str(e)}") raise finally: if 'source_engine' in locals(): source_engine.dispose() if 'target_engine' in locals(): target_engine.dispose() if __name__ == "__main__": # 配置文件路径(根据实际情况修改) config_file = "config.ini" try: transform_and_load_ma_type(config_file) except Exception as e: print(f"程序执行失败: {str(e)}")