目录

​​1简介... 1​​

​​2 准备... 1​​

​​2.1 环境说明... 1​​

​​3 安装... 2​​

​​4 配置... 2​​

​​5 使用... 2​​

​​5.1 验证实验... 2​​

​​5.2 问题分析... 4​​

​​6 延展... 5​​

​​7 总结... 5​​

Mysql迁移到Oracle方法

1简介

基于mysql select into outfile的方式导出文本文件并结合sqlldr导入数据到oracle里

2 准备

2.1 环境说明

1 mysql版本10.3.13-MariaDB,同理其它mysql版本效果类似。

-- 查看mysql版本
SELECT VERSION() AS mysql_Version;

mysql_Version

10.3.13-MariaDB

-- mysql 字符集
show variables like '%char%';

Variable_name

Value

character_set_client

utf8

character_set_connection

utf8

character_set_database

utf8

character_set_filesystem

binary

character_set_results


character_set_server

utf8

character_set_system

utf8

character_sets_dir

E:\Program Files\MariaDB 10.3\share\charsets\

2 oracle版本为11gR2,同理其它版本效果类似。

--查看数据库版本
SELECT * FROM v$version;

BANNER

Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

PL/SQL Release 11.2.0.4.0 - Production

"CORE   11.2.0.4.0  Production"

TNS for Linux: Version 11.2.0.4.0 - Production

NLSRTL Version 11.2.0.4.0 - Production

--查看字符集
SELECT * FROM v$nls_parameters where parameter='NLS_CHARACTERSET';

PARAMETER

VALUE

NLS_CHARACTERSET

AL32UTF8

3

无.

4 配置

5 使用

5.1 验证实验

1) 通过mysql的 select into outfile的方式拼接SQL生成导出txt的语句。并将生成出来的sql语句拷贝出来并保存成export.sql

SELECT
CONCAT('SELECT ',
group_concat('IFNULL(',COLUMN_NAME,','''')'),
' into outfile "\/var\/lib\/mysql-files\/tmp\/data\/',
table_name,
'.txt','" fields terminated by "\\t" lines terminated by ''\\r\\n'' from test.',table_name,';')
from information_schema.`COLUMNS`
WHERE TABLE_schema = 'test'
GROUP BY TABLE_NAME

注:

  1. 这里 /var/lib/mysql-files/tmp/data可以改成其它mysql用户权限访问的目录。
  2. 这里假设export.sql 保存在/var/lib/mysql-files/tmp/目录里。

2) 通过mysql <的方式执行外部的sql文件,这里可以将该命令封装在shell里

#! /bin/sh
mysql -uroot -ppasswd -Dtest<'/var/lib/mysql-files/tmp/export.sql' 1>/tmp/log.log

3) 如果oracle和mysql不在一台服务器上,那么需要通过命令将txt文件拷贝到oracle服务器里。如果在一台服务器上,则忽略这个操作。

scp -r /var/lib/mysql-files/tmp/data/*.txt root@192.168.56.32:/root/script/data/

4) 通过sql拼出sqlldr的ctl文件,拷贝执行出来的内容到imp.txt里

select concat('load data','\r','characterset utf8','\r','INFILE ''\/root\/script\/data\/',table_name,'.txt''','\r','Append into table ',table_name,'\r','fields terminated by '"'\\t'"'','\r','trailing nullcols','\r','(','\r',
group_concat(COLUMN_NAME),

');'
)
from information_schema.`COLUMNS`
WHERE table_schema in('test')
GROUP BY TABLE_NAME

5) 通过python代码按照“;”拆分成ctl文件。

import os

def splitFile(fileIn,dirOut):
file1 = open(fileIn, 'r', encoding='utf-8')
try:
str=""
for line in file1.readlines():
if line.find('.') >0:
fileName=line.split('/')[-1].replace('txt\'','ctl').strip("\n")
print(fileName)
file2 = open(dirOut + '\\' + fileName, 'w', encoding='utf-8')
str=str+" "+line
if line[-2]==";":
#line = line.strip("\n")
###print(str);
file2.write(str.replace(";",'').replace("GXSJC","GXSJC date \"yyyy-mm-dd hh24:mi:ss\""))

str = ""
file2.close()

finally:
file1.close()



if __name__ == '__main__':
splitFile(r'D:\temp\imp.txt',r'D:\temp\impCtls')

6) 生成sqlldr执行脚本,将SQL拼接里的内容拷贝出到Imp.sh内。

select concat('sqlldr userid=test/passwd@Instance  rows=500000 bindsize=30720000 control=/root/script/ctl/' ,table_name )
from information_schema.tables where table_schema='test';

7) 运行Imp.sh并结合log文件对错误进行分析。

5.2 问题分析

  1. 报字符串长度超了,oracle里的长度varchar2最长为4000,而且汉字占用3个字符,所以需要跟mysql里的varchar乘以3;这个仅限oracle字符集是UTF8的情况。
  2. mysql导出txt出现NULL或者\N的情况,解决方法在mysql导出时加IFNULL函数。当前的导出脚本里已经加了。但是建议基于mysql的字典表,对字段可能为NULL的加加上IFNULL函数,其它的不加。
  3.  ORA-01861: literal does not match format string 需要指定时间格式;

可能的时间格式 date 'yyyy-mm-dd hh24:mi:ss',此操作可以在ctl文件里修改,即对应的字段后面加上时间格式转换,如:

Col_name date 'yyyy-mm-dd hh24:mi:ss'

     4. Field in data file exceeds maximum length;

这种错误可能是字段里含有中文字符,解决方法,在ctl里对有问题的字段,后面加char(4000)转换,如:

Col_name char(4000)

      5. ORA-01722: invalid number;

这种错误可能是因为当前表的最后一个字段是数值型的且当前导出的数据行分隔符是\r\n,即回车换行。

解决方法,导出的txt的行分隔符换成\n

     6.导入时出现字段和记录对不上的问题

可能的情况是字段里含有行分隔符\r\n,处理方法是换个行分隔符或者对出错的字段替换\r\n,即

REPLACE(REPLACE(char(13),''),CHAR(10),'')

6 延展

7 总结

暂无.有问题可以咨询如下:

Mysql迁移到Oracle方法_mysql迁移到oracle