(以下文章擷取自筆者的 blog,分享給大家)
在資料庫移轉的部份,原來的資料庫有廠商使用的部份,然後也有筆者自己維護的系統的部份。廠商的部份使用前幾天提到的方式,花了一點時間轉置,基本上沒有太大的問題,系統程式都能正常運行,因此我想筆者這邊的程式應該也可以如法泡製吧。
結果筆者花了一個星期的時間才完成進入測試,相關的過程紀錄如下。
系統架構
基本需求
如同前面所說,原來是想用 MySQL Workbench 的 Database Migrate 功能轉換即可,結果碰到釘子,原因如下。
所以後來是自己寫 Script 處理
bcp "select * from table" queryout "query.csv" -c -t"\t" -r"|" -S Server -U username -P password
...
bcp "open symmetric key ...; select cast(descryptbykey(key, ...) as nvarchar) ... from table2" queryout "table2.csv" -c -t"\t" -r"|" -S Server -U username -P password
...
因為 bcp 不支援 Unicode 輸出 (SQL Server does not support code page 65001 (UTF-8 encoding).),只支援雙字元輸出 (-w),但那看起來會十分奇怪,所以要轉檔成為 UTF-8
使用 load data local infile 來匯入資料
truncate table tab_name;
...
load data local infile 'query.csv' into table tab_name
fields terminated by '\t'
lines terminated by '|'
...
T-SQL | MariaDB SQL |
---|---|
getdate() | now() |
dateadd() | adddate() |
top N ... | ... limit N |
HashBytes('md5', ...) | MD5(...) |
open symmetric key ... by password=passprase ...encryptbykey(key, ...)decryptbykey(key, ...) | aes_encrypt(passphrase, ...) aes_decrypt(passphrase, ...) |
基本上不會有什麼問題,但是在程式裡有類似這樣的動作
select ... from table where idx not in (select idx from table2 where ... limit 10)
會有如下的錯誤
This version of MariaDB doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
不過有神人幫忙,這個是有解的
select ... from table where idx not in (select idx from (select idx from table2 where ... limit 10) as i)
只要多一層 select,不要直接接上 in 就可以解決了
在上面的基本語法轉換以後,基本上 99% 的功能已經是沒有問題了,但是在這最後的 1% 卻花了我好幾天的時間。
這個問題的發生是這樣的,當遇到某些欄位的時候就會發生這個錯誤
[ma-2.0.11][mariadb-10.1.16] Invalid string or buffer length
這還不是一直發生,有的時候會有,有的時候很正常,功能的部份有的會發生,有的不會,這樣就要去看看程式碼有關那些欄位的存取情形與資料庫狀態,但是這就跟基本需求裏面說的相違背 (需要了解更多的 Code),所以首先懷疑是 ODBC 的關係。
換了 1.0 版本更慘,連原來 SQL Statement 都會被截斷,基本上是不能退到 1.0 版了
只好硬著頭皮看 Codes 跟資料庫,終於發現到問題
當欄位是空字串 (不是 Null 喔) 時,透過 ODBC Select 到 ADODB.RecordSet 會有問題 (在其他 client 都沒問題),無論有幾個欄位有這樣的情形,只要有一個它就 Error 給你看
所以就要改寫那些 SQL 語法 (通常都是 select *) 為明確欄位且要先轉為 Null 或是其他的值
原來 (有 a b c d e 5 個欄位,其中 c d e 有可能是空字串)
select * from table where ...
改寫成
select *, (case c when '' then NULL else c end) as c, (case d when '' then ' ' else d end) as d, (case e when '' then 'x' else e end) as e from table where ...
Codes 馬上暴增超多的,Debug 更困難了
以前的 SQL Server ADODB 不會這樣,所以都沒有任何轉換機制,現在就要為了這個寫一堆多餘的 Codes
這個問題我有發個 issue,這個錯誤已經在 2.0.12 版後更新了,感謝神人!讓我第一次感受的社群的活力與速度。
另外有個錯誤訊息,也是一樣的問題。
Data provider or other service returned an E_FAIL status