Sql-Server

如何將 Text 列中的 ISO8859 文本批量轉換為 nvarchar(max) 列中的 UTF8?

  • February 11, 2022

幾天來,我一直在為 MS SQL 數據庫的問題苦苦掙扎。情況如下:我有一個舊的開源 PHP 應用程序(Limesurvey 版本 1.92)在 Windows 2008R2 伺服器上執行,SQL2008R2 作為 RDBMS。我需要將應用程序中的調查遷移到一個新實例,該實例在帶有 MySQL 的 Linux 上執行。新實例是版本3,兩個版本之間的數據庫結構不同。我嘗試使用的方案是在舊伺服器上升級舊版本,然後將調查導出為導出文件,我可以將其導入到新應用程序中。它運作良好。除了我因為字元編碼問題而被卡住。舊的應用程序(Web 應用程序)使用 UTF-8。但數據庫僅使用 VARCHAR 和 TEXT 列。因此 UTF-8 字元在這些列中使用幾個字節儲存:例如,é 儲存為 é。當我升級應用程序時,升級腳本會更改表的結構:TEXT 列變為 NVARCHAR(MAX),但列中的內容未轉換為 UTF-8。因此,我正在尋找一種將 NVARCHAR(MAX) 列中的內容從 ISO8859 更改為 UTF-8 的方法。該數據庫有大約 200 個表,大小為 600MB。

SQL Server 2008r2 dopes 不支持 UTF8(這種支持在即將到來的 2019 版本之前不會出現)它只支持 UCS2(本質上是 UTF16 的子集)。因此,SQL Server 本身不太可能有實用的解決方案。

您可能需要編寫一個工具來提取數據、轉換數據並使用新轉換的值更新數據庫。

在重讀這個問題時,我注意到您提到 mysql 作為目標數據庫,儘管您的標籤沒有提到這一點。您提到的類型(NVARCHAR等)不是 mysql 類型。您可能需要澄清問題並更新標籤。

這個問題有點不清楚,因為表明需要遷移到 MySQL,但只提到 SQL Server 數據類型。您的意思是說“升級”過程是先轉換 SQL Server 中的所有內容,然後將數據導出並導入 MySQL 嗎?根據情況的具體情況,聽起來您至少有兩種選擇:

  1. 如果應用程序確實儲存了 UTF-8 字節é而不是é,則您可以使用列排序規則的程式碼頁將VARCHAR/TEXT列中的數據導出到文本文件中。您可以使用以下查詢找到它:
SELECT col.[name],
      col.[collation_name],
      COLLATIONPROPERTY(col.[collation_name], 'CodePage') AS [CodePage]
FROM   sys.columns col
WHERE  col.[object_id] = OBJECT_ID(N'dbo.InfoSchemaBug')
AND    col.[collation_name] IS NOT NULL;

使用相同的程式碼頁將確保寫入文件的字節是列中已經存在的字節,並且列中的字節(而不是字元)是正確的。

數據導出後,只需導入 MySQL,這次告訴導入過程該文件實際上編碼為 UTF-8。由於字節一開始是 UTF-8,所以它仍然是 UTF-8 數據(只要在導出期間字節沒有改變)。 2. 由於內部 UTF-8 支持直到 SQL Server 2019 才開始,您仍然可以將數據就地轉換為 Unicode (UTF-16),以便可以將其導出為“Unicode”(即 UTF-16 Little Endian)只要您指出該文件被編碼為 UTF-16 LE,該文件仍應可導入 MySQL。您可以嘗試以下使用轉換為XML(從,但如果您針對已轉換為列VARCHAR執行,則寫入處理)來處理轉換的方法:NVARCHAR

CREATE TABLE #UTF8bytes
(
 [Data] NVARCHAR(MAX)
);

INSERT INTO #UTF8bytes ([Data]) VALUES (N'é&');

SELECT *,
      CONVERT(NVARCHAR(MAX),
              CONVERT(XML,
                  '<?xml version="1.0" encoding="utf-8" standalone="yes" ?><!--'
                  + CONVERT(VARCHAR(MAX), tmp.[Data] COLLATE Latin1_General_100_CI_AS)
                  + '-->'
                     )
             ) AS [Converted]
FROM   #UTF8bytes tmp;
/*
Data    Converted
é&     <!--é&-->
*/


UPDATE tmp
SET    tmp.[Data] = CONVERT(NVARCHAR(MAX),
              CONVERT(XML,
                  '<?xml version="1.0" encoding="utf-8" standalone="yes" ?><!--'
                  + CONVERT(VARCHAR(MAX), tmp.[Data] COLLATE Latin1_General_100_CI_AS)
                  + '-->'
                     )
             )
FROM   #UTF8bytes tmp;


SELECT *
FROM   #UTF8bytes tmp;
-- <!--é&-->

之後,您只需<!--要從每個值的開頭和每個值-->的末尾刪除 。包含這些以強制現有數據成為 XML 註釋,它接受 XML 特殊字元,例如<"&. 只要數據中還沒有包含 the<!--或 the -->,這應該可以工作。而且,您可能會SUBSTRINGUPDATE語句中添加一兩個值,以便在與轉換相同的操作中刪除這兩個值。

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