Sql-Server

SQL Server 到 MySQL 的遷移 - 如何在 SQL Server 中刪除 UCS-2 代理對?

  • May 19, 2017

我的任務是將 SQL Server 2005 數據庫遷移到 MySQL 5.6(這些都是本地執行的數據庫伺服器),非常感謝一些幫助。

——–編輯 - 已回答—–

現在這個問題已經解決了。我使用 Remus Rusanu 的建議來查找具有這些代理對字元的行,CHARINDEX並決定使用它SUBSTRING來排除麻煩的字元,如下所示:

UPDATE test
SET a = SUBSTRING(a,  1,   (CHARINDEX(0x83dc, CAST(a AS VARBINARY(8000)))+1)/2 - 1) -- string before the unwanted character
+ SUBSTRING(a, (CHARINDEX(0x83dc, CAST(a AS VARBINARY(8000)))+1)/2 +1, LEN(a) ) -- string after the unwanted character
WHERE CHARINDEX(0x83dc, CAST(a AS VARBINARY(8000))) % 2 = 1 -- only odd numbered charindexes (to signify match at beginning of byte pair character)

—————————–

  • SQL Server 源數據庫有latin1排序規則(所以有 ISO 8859-1 字元集對嗎?)但沒有任何char/varchar欄位(任何字元串欄位都是nvarchar/nchar),因此所有這些數據都應該使用 UCS-2 字元集。
  • MySQL 目標數據庫需要 UTF-8 字元集。

我決定在最新版本的 MySQL 工作台中使用數據庫遷移工具包。起初它執行良好並按預期遷移了所有內容。但是在 SQL Server 數據庫中遇到 UCS-2 代理對字元時,我完全被絆倒了。

遷移工具包可複製表程序沒有提供非常有用的錯誤消息:

wstring 的字元集轉換期間出錯:沒有錯誤。

它也沒有提供有關導致問題的數據的任何欄位/行資訊,並且會在 100 行的塊內失敗。因此,在最後一次成功插入後搜尋 100 行後,我發現問題似乎是由其中一個 nvarchar 欄位中的兩個 UCS-2 字元引起的。它們在 UCS-2 字元集中被列為代理項對。它們特別是字元 DBC0 和 DC83(我通過查看該欄位的二進制數據並將字節對(小端序)與成功遷移的數據進行比較得到了這一點)。

當從 SQL Server 數據庫中刪除此代理對時,該行已成功遷移到 MySQL。

這是問題所在:

我試圖在測試 SQL Server 表中搜尋這些字元(這個圖表表只是一個 nvarchar 欄位的各種測試字元串)以準備替換腳本並不斷得到奇怪的結果……我一定做錯了什麼。

正在尋找

SELECT * FROM chartest WHERE text LIKE NCHAR(0xdc83)

將返回任何代理對字元(無論它是否使用 DC83),但顯然,僅當它是該欄位中唯一的字元(或該對的一部分)時。這沒什麼大不了的,因為無論如何我都想刪除這些實例(我不喜歡刪除這樣的數據,但我認為我們負擔得起)。

正在尋找

SELECT * FROM chartest WHERE text LIKE '%' + NCHAR(0xdc83) + '%'

將返回每一行!無論欄位中是否存在 unicode 字元,更不用說 DC83 字元了。有沒有更好的方法來查找和替換這些字元?或者我應該嘗試其他什麼?

我還嘗試將目標數據庫、表和欄位字元集設置為 UCS-2,但似乎沒有什麼區別。

我還應該提到,此遷移使用實時數據(約 50GB 數據庫!),而其中一個提供數據的站點已離線,因此任何解決方案都需要快速執行…

我非常感謝任何建議!如果我遺漏了任何資訊,請告訴我。

您需要從 UTF-8 獲取數據並使用 iconv 之類的東西將其轉換為 UCS-2LE。例如,使用範例中的字元:

echo "010000: dcb3" | xxd -r -s -0x10000 | iconv -f "UTF-8" -t "UCS-2LE" | xxd
0000000: 3307 

現在我不確定 UTF-8 \xdcb3 是什麼字元,但顯然它對 UCS-2LE 的正確翻譯是\U0733. 如果您\0xDCB3在 SQL Server 中有,則表示它在導入之前未翻譯成 UCS-2LE。您不應該在 NVARCHAR 欄位中有代理,UCS-2 是“代理不可知論”。請參閱UCS-2 與 UTF-16(不完全是 Kramer 與 Kramer)

我不是 MySQL 工具集的專家,所​​以我不能說應該執行 iconv 的步驟是什麼。

更新


要找到帶有代理項的記錄,您必須轉向二進製表示,因為任何字元函式都會將代理項威脅為“特殊”:。幸運的是,字元串操作函式也可以在具有預期語義的二進製文件上工作。例如。字元索引

insert into test(a) values  (N'a');
insert into test(a) values  (NCHAR(0xdc83));
insert into test(a) values  (N'b');
go

select * from test where charindex(0x83dc, cast(a as varbinary(8000))) > 0;

引用自:https://dba.stackexchange.com/questions/37343