Sql-Server

如何將 Unicode 字元詳細插入 varchar 數據庫?

  • January 6, 2020

我需要將此字元“●”插入到VARCHARMSSQL 數據庫的列中,並將排序規則設置為SQL_Latin1_General_CP1_CI_AS(或至少模擬我的 Python + Windows MSSQL 驅動程序可能已經完成的操作)。我試圖從我的客戶那裡插入它,但它被插入為?.

在 Python 中檢查的十六進制值\xe2\x97\x8f是二進制 226、151、143。

排序規則說明 226 已定義,但 143 和 151 未定義。所以我最好是插入226?

我做這個練習的原因是我們的應用程序早先將這個字元插入到 DB 中。在這一點上,我不知道它是如何進入的,因為它通過一個帶有 Windows MSSQL 驅動程序的 Python 應用程序,我們的數據庫團隊編寫了一個腳本來糾正它,顯然它被替換為“?”。

現在我只是想重現這個場景來問他們為什麼它被替換為“?” 因為我們在應用程序中將其替換為空。由於我的應用程序已經修復了這個問題(我們刪除了任何大於 127 的內容),我試圖直接從後端模擬它以證明它正在被替換為“?” 這實際上是我的主張,我認為它已經完成,因為它在更新查詢中說“整理”。

UPDATE pr_response
SET nur_respon =
REPLACE (nur_respon,
    SUBSTRING(nur_respon, PATINDEX('%[^ !-~]%' COLLATE Latin1_General_BIN, nur_respon), 1),
        '')
WHERE PATINDEX('%[^ !-~]%' COLLATE Latin1_General_BIN, nur_respon) > 0

這是刪除 Non-ASCII-Data > 127 的好腳本嗎?有人可以用簡單的英語解釋這個查詢嗎?

我需要將此字元“●”插入一VARCHAR列… 排序規則設置為SQL_Latin1_General_CP1_CI_AS… 我做這個練習的原因是我們的應用程序早先將此字元插入數據庫。

不,該應用程序沒有使用排序規則將此字元 ( Black Circle U+25CF ) 插入到VARCHAR列中[SQL_]Latin1_General...。Latin1_General 排序規則使用程式碼頁 1252,它沒有這樣的字元,似乎也沒有“最合適”的映射將其轉換為類似的東西。

該字元確實存在於某些程式碼頁中,例如韓語和日語排序規則使用的程式碼頁,如以下查詢所示(兩者都是雙字節字元集,這就是轉換為VARBINARY顯示兩個字節而不是一個字節的原因):

SELECT CONVERT(VARCHAR(10), N'●' COLLATE Korean_100_CI_AS),
      CONVERT(VARBINARY(10), CONVERT(VARCHAR(10), N'●' COLLATE Korean_100_CI_AS));
-- ●    0xA1DC

SELECT CONVERT(VARCHAR(10), N'●' COLLATE Japanese_XJIS_100_CI_AS),
      CONVERT(VARBINARY(10), CONVERT(VARCHAR(10), N'●' COLLATE Japanese_XJIS_100_CI_AS));
-- ●    0x819C

SELECT CONVERT(VARCHAR(10), N'●' COLLATE Latin1_General_100_CI_AS),
      CONVERT(VARBINARY(10), CONVERT(VARCHAR(10), N'●' COLLATE Latin1_General_100_CI_AS));
-- ?    0x3F

但是,該應用程序可能插入了“•”(Bullet U+2022),它看起來非常相似,只是小了一點。“項目符號”字元在程式碼頁 1252(Dec 149 或十六進制 0x95)中可用。

我們的數據庫團隊編寫了一個腳本來糾正它,顯然它被替換為“?”

那麼,將“●”替換為“?” 聽起來不像修復它;-)。

現在我只是想重現這個場景來問他們為什麼它被替換為“?” 因為我們在應用程序中將其替換為空。由於我的應用程序已經解決了這個問題(我們刪除了任何大於 127 的內容)

不管技術細節如何,很明顯這兩個陳述不能同時為真:不能用“?”代替。在訪問 SQL Server 之前被刪除。顯然,應用程式碼沒有對此進行修復,並且不會刪除值超過 127 的所有內容。它正在被轉換為“?” 在 SQL Server 中,因為正在插入該字元但在程式碼頁 1252 中不存在。

我認為它已經完成,因為它在更新查詢中顯示“COLLATE”。

不,通過COLLATE關鍵字強制二進制排序規則不會將此字元更改為“?”。列的排序規則 ( SQL_Latin1_General_CP1_CI_AS) 和顯式排序規則 ( Latin1_General_BIN) 都使用程式碼頁 1252,因此不會更改任何字元。

“●”字元被替換為“?” 因為它被插入到VARCHAR列中。並且一旦它作為問號插入,就沒有什麼需要清理的了,也沒有辦法將該問號辨識為最初來自其他東西,而不是預期的問號。

這是刪除 Non-ASCII-Data > 127 的好腳本嗎?有人可以用簡單的英語解釋這個查詢嗎?

該查詢查找任何出現的 ASCII 值大於 127 的字元(這就是它PATINDEX所做的),然後獲取任何這樣的字元(這就是它SUBSTRING所做的),然後用空替換該列中該字元的所有出現字元串(這就是它的REPLACE作用)。UPDATE如果沒有找到 ASCII 值超過 127 的字元,則查詢不會執行任何操作。

此查詢一次僅適用於一個字元。因此,如果一列有 2 個或多個 ASCII 值大於 127 的字元不是相同的 ASCII 值,則需要多次執行腳本。

在這種特殊情況下(即用“?”替換“●”),該查詢將無濟於事,因為該轉換正在進行中。該查詢僅處理 ASCII 值為 128 - 255 的字元,但“●”不是其中一個字元,因為它一開始就不可能出現在此列中。

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