Oracle迁移到MySQL时数据类型转换问题
Posted 业余砖家
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle迁移到MySQL时数据类型转换问题相关的知识,希望对你有一定的参考价值。
最近在做“去O”(去除Oracle数据库)的相关工作,需要将Oracle表结构转换成MySQL的表结构。这里面最重要的一点就是字段数据类型的变化。
1.ORACLE常用的数据类型与MySQL的对应关系
2.Oracle 中 varchar2(N) 与 varchar2(N char) 的区别
varchar(N)中是可以存储N个字节,而varchar(N char)是可以存储N个字符。
(对于UTF-8数据集来说:中文占两个字节,而英文占一个字节)
1、varchar2(N):可以存储N byte长度,与字符数无关;例如varchar2(3),可以存储3个byte长度,如\'啊a\'、\'aaa\',与字符数无关;
2、varchar2(N char):可以存储N个字符(包括字母和汉字),与字节(byte)长度无关;例如varchar2(3 char),可以存储3个字符(包括字母和汉字),如\'啊啊啊\'、\'aaa\'、\'啊aa\',与字节(byte)长度无关;
说明:对于字符集为UTF-8的MySQL数据库,varchar(10)不区分中英文,可以存储10个中文汉字,或者10个字母或数字。所以从Oracle的Varchar2类型转换成varchar类型,长度保持不变即可满足。
3.number数值类型转化
最复杂莫过于number(p,s),以这个举例来说明如何转换。
p是指有效位数,s是小数位,需要以p和s的实际取值来确定mysql的字段类型:
当p,s均为空时,此时需要参考表内的实际数值或者根据具体业务来确定转换的类型。参考实际数值时,可以采用获取表中max(length(column_name))-1(包含一个小数点)来确定p,用max(length(column_name)-instr(column_name ||\'.\',\'.\'))(查找小数点后的位数)来确定s的值。
另外,一定要注意MySQL的int(2)这种写法,并不是smallint的别名,不管是int(2)还是int(8),实际都是int。
4.其他注意事项
除了最复杂的number类型以外,其他字段还有几点小建议:
(1)除非要修改设计以支持秒以下级别的精度,Date最好转换为datetime而不要转为TIMESTAMP,因为TIMESTAMP存在2038年问题。
(2)ORACLE FLOAT不要转为MYSQL FLOAT,要转为DOUBILE避免精度丢失。
(3)处理char时,要注意最大的长度。
(4)BLOB,CLOB转换时,MYSQL也有众多不同长度的类型选择,最好根据实际业务需要和业务数据来判断选择何种长度。
本文来自博客园,作者:业余砖家,转载请注明原文链接:https://www.cnblogs.com/yeyuzhuanjia/p/17431979.html
SQL Alchemy - 从 Oracle 迁移到 MySQL 的 Python 脚本
【中文标题】SQL Alchemy - 从 Oracle 迁移到 MySQL 的 Python 脚本【英文标题】:SQL Alchemy - Python script to migrate from Oracle to MySQL 【发布时间】:2021-08-26 17:09:18 【问题描述】:我正在尝试使用 cx_Oracle 和 SQL Alchemy 执行从 Oracle 到 MySQL 的批量提取/加载。
我在网上找到了这个示例,它适用于大多数数据类型,但在 Blob 数据类型中失败:
https://vbaoverall.com/transfer-data-from-oracle-to-mysql-using-sqlalchemy-python/
我有大约 43 个表,其中大约 12 个有 BLOB
数据类型。
import cx_Oracle
import pandas as pd
from sqlalchemy import create_engine
import pymysql
import warnings
warnings.filterwarnings('ignore')
# list out all 43 tables:
table_list = [
"FILE",
"ATTACHMENT",
"DOCUMENTS",
"USERS",
"INFO",
"ONE",
"TWO",
"THREE",
"FOUR",
"...."
]
# Set Oralce Connection
dsn_tns = cx_Oracle.makedsn('source.example.com', '1530', service_name='test')
oracle_connection = cx_Oracle.connect(user='root', password='toot', dsn=dsn_tns)
# Open Oracle cursor
cursor = oracle_connection.cursor()
# set mysql connection with foreign key checks
mysql_engine = create_engine("mysql+pymysql://root:toot@target.example.com:3306/target")
mysql_engine.execute("SET FOREIGN_KEY_CHECKS=0")
# loop thru tables:
for table in table_list:
# select from oracle
sql = "SELECT * FROM " + table
# read into pandas df
data=pd.read_sql(sql, oracle_connection)
# insert into mysql
mysql_engine.execute("TRUNCATE TABLE "+table)
data.to_sql(table, con=mysql_engine, if_exists='append', index=False, chunksize=10000)
print(": sucessfully inserted rows.".format(table, data.shape[0]))
# update foreign key checks
mysql_engine.execute("SET FOREIGN_KEY_CHECKS=1")
#close connection
oracle_connection.close()
mysql_engine.dispose()
这是我得到的错误:
return "'%s'" % escape_string(str(value), mapping)
TypeError: __str__ returned non-string (type bytes)
【问题讨论】:
您是否尝试过使用to_sql()
的dtype=
参数来显式设置列类型?
我在尝试这个时收到了一个不同的错误:dtype = dtype['FILE_CONTENT'] = sqlalchemy.types.BLOB
我尝试了BLOB
和BINARY
并收到了这个错误:sqlalchemy.exc.StatementError: (builtins.TypeError) cannot convert 'cx_Oracle.LOB' object to bytes
实际上,当我将类型更改为PickleType
时,它起作用了。谢谢@GordThompson
【参考方案1】:
感谢@Gord Thompson,我发现我只需要指定dtype=
import cx_Oracle
import pandas as pd
from sqlalchemy import create_engine
import sqlalchemy
import pymysql
import warnings
warnings.filterwarnings('ignore')
table_list = [
"FILE",
"ATTACHMENT",
"DOCUMENTS",
"USERS",
"INFO",
"ONE",
"TWO",
"THREE",
"FOUR",
"...."
]
# Set Oralce Connection
dsn_tns = cx_Oracle.makedsn('source.example.com', '1530', service_name='test')
oracle_connection = cx_Oracle.connect(user='root', password='toot', dsn=dsn_tns)
# Open Oracle cursor
cursor = oracle_connection.cursor()
# set mysql connection with foreign key checks
mysql_engine = create_engine("mysql+pymysql://root:toot@target.example.com:3306/target")
mysql_engine.execute("SET FOREIGN_KEY_CHECKS=0")
for table in table_list:
# select from oracle
sql = "SELECT * FROM " + table
# read into pandas df
data=pd.read_sql(sql, oracle_connection)
dtype =
if table == "ATTACHMENT":
dtype['FILE_CONTENT'] = sqlalchemy.types.PickleType
# insert into mysql
mysql_engine.execute("TRUNCATE TABLE "+table)
data.to_sql(table, con=mysql_engine, if_exists='append', index = False, chunksize =10000, dtype=dtype)
print(": sucessfully inserted rows.".format(table, data.shape[0]))
# update foreign key checks
mysql_engine.execute("SET FOREIGN_KEY_CHECKS=1")
#close connection
oracle_connection.close()
mysql_engine.dispose()
【讨论】:
以上是关于Oracle迁移到MySQL时数据类型转换问题的主要内容,如果未能解决你的问题,请参考以下文章