找到一种不错的从SQLServer转成Mysql数据库的方法
程序员文章站
2023-11-27 23:01:10
年初的时候一直在做一个网站mssql2000 -> mysql5的迁移工作,因为采用了不同的程序系统,所以主要问题在数据的迁移。由于2个系统数据库...
年初的时候一直在做一个网站mssql2000 -> mysql5的迁移工作,因为采用了不同的程序系统,所以主要问题在数据的迁移。由于2个系统数据库结构差异非常大,不方便采取sql server里导入mysql的odbc数据源的功能(也不推荐这么做,字段类型等不同点会搞死人的~),因此就在windows下自己写php脚本从sqlserver里读数据,然后按照新系统的需要处理之后插入mysql里面,灵活也比较方便。实际过程主要有下面几个问题:
1、数据库的连接,主要是连接sql server。主要有3种方法:
1.1 利用php中的mssql_系列函数,这个与使用mysql_系列函数类似,不过要打开php.ini中相关扩展(extension=php_mssql.dll)。
1.2 利用odbc连接,由于抽象了具体数据库,所以没有办法利用数据表字段名=>数组键名的特性,在针对具体应用时不是很方便,代码形式:
$conn = odbc_connect("datasource","username","password");
$sql = "select * from news";
$cur= odbc_exec($conn, $sql);
while(odbc_fetch_row($cur)){
$field1 = odbc_result($cur,1);
$field2 = odbc_result($cur,2);
//do something
}
1.3 使用pdo - php5中加入数据对象抽象层,作为官方推出的数据访问接口,优点有很多,比如支持参数绑定以防止sql注入;对于不同数据库加载不同驱动即可,程序代码是一致的,便于移植等等,相信应该是大势所趋。不过由于用了php5全新的面向对象特性,需要php5的支持,5.1可以直接使用,5需要装pecl,另外还要修改php.ini,增加:extension=php_pdo_mysql.dll和extension=php_pdo_mssql.dll,实际代码如下:
try {
$dbh=new pdo("mssql:dbname=xxx;host=localhost",
"root", "password");//connect to db
} catch (pdoexception $e) {
print "error!: " . $e->getmessage();//error message
die();
}
$stmt = $dbh->prepare("select * from news");//stmt handle $stmt
if ($stmt->execute()) {
while ($row = $stmt->fetch()) {
//do something
}
}
$stmt2 = $mssql->prepare("insert into news
(title,author) values (:title, :author)");
$stmt2->bindparam(':title', $title);
$stmt2->bindparam(':author', $author);
$stmt2->execute();
$dbh = null;// close connection这里要提醒下的是mssql里面是没有mysql中limit这个语法的。
2、text字段被截断的问题。
上面尝试了3种连接数据库方法,是因为当初连上mssql后select出来的数据总是只有4k长度,以为是连接方式限制导致的,所以换了几种都是这样,最后查了资料才知道,是php.ini里面这2句配置的问题:
; valid range 0 - 2147483647. default = 4096.
mssql.textlimit = 4096
; valid range 0 - 2147483647. default = 4096.
mssql.textsize = 4096
把4096改成-1(代表无限制)即可,也可以使用mssql_query("set textsize 65536");来实现。
3.两种数据库字段类型不同的问题有2个地方需要讲一下,一个是字段支持最大长度要注意,以免插入数据库时候被截断,另外一个就是日期格式的问题了,我比较喜欢用unix时间戳。在连mssql时候可以用 "select unix_timestamp(created) from news" 来实现mssql里面datetime到mysql里时间戳的转换。不过迁移时候一次要提取表中所有字段,像上面这种方法就没有简单的"select * from news"简洁,需要罗列所有字段。实际可以直接select出来,得到的是一个字符串,比如在mssql里面是2006-01-01 12:01,取出来的字符串是"2006 一月 01 12:01"(有些奇怪,不知道为什么会产生中文)。用下面这个函数可以转换成时间戳:
function converttime($timestring){
if($timestring == null){
return 0;
}
$time = explode(" ",$timestring);
$year = $time[0];
switch ($time[1]){
case "一月":$month = "1";break;
case "二月":$month = "2";break;
case "三月":$month = "3";break;
case "四月":$month = "4";break;
case "五月":$month = "5";break;
case "六月":$month = "6";break;
case "七月":$month = "7";break;
case "八月":$month = "8";break;
case "九月":$month = "9";break;
case "十月":$month = "10";break;
case "十一月":$month = "11";break;
case "十二月":$month = "12";break;
default:break;
}
$day = $time[2];
$h = 0;
$m = 0;
$s = 0;
if(!empty($time[3])){
$time2 = explode(":",$time[3]);
$h = $time2[0];
$i = $time2[1];
}
//return date("y-m-d h:i:s",mktime($h,$i,$s,$month,$day,$year));
return mktime($h,$i,$s,$month,$day,$year);
}最后转换脚本写完了可以在cmd窗口里面用php.exe abc.php来执行,这种方式是没有超时时间的,适合迁移大批量数据。
基本上就是这些内容,希望对大家有帮助。
update(06/05/05):关于时间戳的转换,在php.ini中加上
mssql.datetimeconvert = off
后就能得到类似2006-01-01 12:01不带有中文的格式了。
1、数据库的连接,主要是连接sql server。主要有3种方法:
1.1 利用php中的mssql_系列函数,这个与使用mysql_系列函数类似,不过要打开php.ini中相关扩展(extension=php_mssql.dll)。
1.2 利用odbc连接,由于抽象了具体数据库,所以没有办法利用数据表字段名=>数组键名的特性,在针对具体应用时不是很方便,代码形式:
$conn = odbc_connect("datasource","username","password");
$sql = "select * from news";
$cur= odbc_exec($conn, $sql);
while(odbc_fetch_row($cur)){
$field1 = odbc_result($cur,1);
$field2 = odbc_result($cur,2);
//do something
}
1.3 使用pdo - php5中加入数据对象抽象层,作为官方推出的数据访问接口,优点有很多,比如支持参数绑定以防止sql注入;对于不同数据库加载不同驱动即可,程序代码是一致的,便于移植等等,相信应该是大势所趋。不过由于用了php5全新的面向对象特性,需要php5的支持,5.1可以直接使用,5需要装pecl,另外还要修改php.ini,增加:extension=php_pdo_mysql.dll和extension=php_pdo_mssql.dll,实际代码如下:
try {
$dbh=new pdo("mssql:dbname=xxx;host=localhost",
"root", "password");//connect to db
} catch (pdoexception $e) {
print "error!: " . $e->getmessage();//error message
die();
}
$stmt = $dbh->prepare("select * from news");//stmt handle $stmt
if ($stmt->execute()) {
while ($row = $stmt->fetch()) {
//do something
}
}
$stmt2 = $mssql->prepare("insert into news
(title,author) values (:title, :author)");
$stmt2->bindparam(':title', $title);
$stmt2->bindparam(':author', $author);
$stmt2->execute();
$dbh = null;// close connection这里要提醒下的是mssql里面是没有mysql中limit这个语法的。
2、text字段被截断的问题。
上面尝试了3种连接数据库方法,是因为当初连上mssql后select出来的数据总是只有4k长度,以为是连接方式限制导致的,所以换了几种都是这样,最后查了资料才知道,是php.ini里面这2句配置的问题:
; valid range 0 - 2147483647. default = 4096.
mssql.textlimit = 4096
; valid range 0 - 2147483647. default = 4096.
mssql.textsize = 4096
把4096改成-1(代表无限制)即可,也可以使用mssql_query("set textsize 65536");来实现。
3.两种数据库字段类型不同的问题有2个地方需要讲一下,一个是字段支持最大长度要注意,以免插入数据库时候被截断,另外一个就是日期格式的问题了,我比较喜欢用unix时间戳。在连mssql时候可以用 "select unix_timestamp(created) from news" 来实现mssql里面datetime到mysql里时间戳的转换。不过迁移时候一次要提取表中所有字段,像上面这种方法就没有简单的"select * from news"简洁,需要罗列所有字段。实际可以直接select出来,得到的是一个字符串,比如在mssql里面是2006-01-01 12:01,取出来的字符串是"2006 一月 01 12:01"(有些奇怪,不知道为什么会产生中文)。用下面这个函数可以转换成时间戳:
function converttime($timestring){
if($timestring == null){
return 0;
}
$time = explode(" ",$timestring);
$year = $time[0];
switch ($time[1]){
case "一月":$month = "1";break;
case "二月":$month = "2";break;
case "三月":$month = "3";break;
case "四月":$month = "4";break;
case "五月":$month = "5";break;
case "六月":$month = "6";break;
case "七月":$month = "7";break;
case "八月":$month = "8";break;
case "九月":$month = "9";break;
case "十月":$month = "10";break;
case "十一月":$month = "11";break;
case "十二月":$month = "12";break;
default:break;
}
$day = $time[2];
$h = 0;
$m = 0;
$s = 0;
if(!empty($time[3])){
$time2 = explode(":",$time[3]);
$h = $time2[0];
$i = $time2[1];
}
//return date("y-m-d h:i:s",mktime($h,$i,$s,$month,$day,$year));
return mktime($h,$i,$s,$month,$day,$year);
}最后转换脚本写完了可以在cmd窗口里面用php.exe abc.php来执行,这种方式是没有超时时间的,适合迁移大批量数据。
基本上就是这些内容,希望对大家有帮助。
update(06/05/05):关于时间戳的转换,在php.ini中加上
mssql.datetimeconvert = off
后就能得到类似2006-01-01 12:01不带有中文的格式了。