终于拿树莓派干了件正事儿,手动把数据从mysql迁移到mssql。

昨天领到一个任务,把某mysql里的表和数据都迁移到MS SQL SERVER。手头拿到的唯一资料就是已从mysql导出的SQL语句脚本,包括创建表和插数据。

最初的想法是直接在ssms里改脚本,把不兼容的地方改掉。无奈太多坑要填,语法过了内容又不过,评估下来工作量太大,只好另想它法。

想了半天,认为可以这样尝试:
1、搞个mysql服务器,用给出的脚本先把数据库还原;
2、MSSQL服务器(其实就是我的笔记本电脑充当了)上装一个mysql的ODBC驱动,再建一个系统DSN以便能直连mysql;
3、MSSQL服务器上通过刚才的ODBC建一个Linked Server到mysql,最后就能在ssms里select into mysql的数据到MSSQL上。

感觉靠谱,值得一试。

看了下SQL脚本,一共十来张表,其中三四张表的记录数在三四千的量级,别的表都在一千以内,少的也就几十上百条,那也不要装什么虚拟机了,直接把我的树莓派拿来用算了。

第一次正儿八经玩mysql,先装了再说,有坑填坑。
sudo apt-get install mysql-server mysql-client
** 注 **:在Raspbian Buster 中改成了 sudo apt-get install mariadb-server mariadb-client

这个较新版本的mysql没要求当场输密码,不过可以运行sudo mysql_secure_installation,仔细看提示,在这里面输入密码,然后继续一步步设置其它的安全选项。看它意思,root只需要在本地做一些授权工作就行了,安全起见并不需要远程访问。

我先授权一个pi账号试试。
sudo mysql -u root -p
输入刚才设置过的密码。然后:
GRANT ALL PRIVILEGES ON KY.* TO 'pi'@'localhost' IDENTIFIED BY 'password123';
这句话的意思是,授予pi这个账号在本机上(本例中就是我的树莓派),对KY数据库具有特权,前提是输对密码password123。

输入quit退出,重新用sudo mysql -u pi -p登录。运行创建KY数据库的SQL语句:create database KY; 成功。但再想create database 其它数据库就被拒绝了。(如果确有必要,grant可以用*.*使其可以创建任意数据库及其子对象。如果改用'pi'@'%'则能启用允许在远程PC上登录。对于我们之后的情况这是必须的,因为必须要从我的笔记本电脑连接树莓派。另外必须指出,%并不包含localhost。)

个人理解,mysql更像是“预约准入制”,而MSSQL更像是标准的“准入制”。

有了库,接下来该建表插数据了。假设脚本文件名是~/Public/test.sql。
运行命令行sudo mysql pi -u ki -p < /home/pi/Public/test.sql
记得脚本的第一句写use KY;。当然也可以不写,但是必须加个-D参数在命令行里直接指定数据库。

还有一个图形化的方法稍微复杂点,使用phpmyadmin,参考https://pimylifeup.com/raspberry-pi-mysql-phpmyadmin/。
核心步骤是,先装apache2(也可以是nginx),然后装phpmyadmin
sudo apt-get install python-mysqldb
sudo apt-get install apache2 phpmyadmin
需要配置apache2的配置文件:
sudo vim /etc/apache2/apache2.conf
加一句:Include /etc/phpmyadmin/apache.conf
最后重启服务。
sudo /etc/init.d/apache2 restart

如果一切顺利,访问网址http://树莓派IP/phpmyadmin/。这样可以贴上SQL语句慢慢执行了。缺点是慢,优点是很直观,尤其是在有坑要填的情况下。
================================================
第一阶段完成,通过SQL语句顺利(确定顺利?)把数据库还原到了树莓派上。

第二阶段简单,去https://dev.mysql.com/downloads/connector/odbc/下载相应驱动。安装好以后,Windows里配置一个系统DSN:
Data Source Name:随便写。我填了RPI
TCP/IP Server:树莓派IP地址
Port:默认的3306
User:pi(需要在mysql里配置为'pi'@'%')
Password:密码
Database:KY
然后按Test。此时应该过不了的。telnet 树莓派IP 3306,确认连接不上。

这是因为mysql默认在网络层面也没有开放远程访问。需要改/etc/mysql/my.cnf,在最后加一句:bind-address = 0.0.0.0
然后重启mysql服务:sudo /etc/init.d/mysql restart

** 注 **:在Raspbian Buster中可以修改 /etc/mysql/mariadb.conf.d/50-server.cnf,这样可以规避下面提到的需要--no-defaults参数的问题。

再telnet一下,应该就有反应了。按ODBC的Test按钮,一切正常的话可以测通。

但会出现一个新坑:试试sudo mysql -u 用户名 -p,发现报错无法解析bind-address。解决办法很简单,再加一个参数 --no-defaults即可(作为第一个参数)。
================================================
终于到了第三阶段了。

MSSQL里新建一个链接服务器:
服务器填树莓派IP地址(我的是192.168.1.113);
提供程序写OLE DB Provider for ODBC;
产品名称写MySQL;
数据源写RPI;
安全性选“使用登录名的当前安全上下文连接”
确定即可。

然后可以写SQL语句测试。比方说:
select * from openquery([192.168.1.113],'select * from users')
这样导入就很简单了。select * into dbo.users from openquery([192.168.1.113],'select * from users') 就能把users表复制到MSSQL里了。

当然实际操作时还是继续趟坑,我遇到两个:
1、插入时遇到了意外的null。这个可能是数据质量标准不兼容造成的。比如,日期类型,mysql允许0000-00-00但mssql不允许,我猜它就自动转成null了,但是字段定义又不允许null所以报错。解决办法是先在mysql里把0000-00-00的日期都update成一个合法(尽管可以不合理)的日期值。
2、'[MSDASQL].userlevel' 所需的数据长度不匹配。所需的(最大)数据长度为 28,但返回的数据长度为 10。
解决办法:在相应的字段上做cast。select * into users from openquery([192.168.1.113],'select 。。。 ,cast(userlevel as char(50)) as userlevel,。。。 from users')

一个个表手动导完,最后把mssql做个全备份,打完收工。