將列從 NVARCHAR 轉換為 VARCHAR
我有幾張有很多
NVARCHAR(MAX)
列的大桌子。該數據庫僅供美國使用,我認為任何列中都沒有任何外來字元或字母,所以我想調查一下:
- 將其中許多列從 更改
NVARCHAR
為VARCHAR
,以及- 根據我所做的一些數據分析,將這些列調整為更合適的大小。例如,我知道其中一些列中數據的最大長度只有大約 30 個字元,所以
NVARCHAR(MAX)
看起來有點矯枉過正。我也試圖限制隱式轉換。
如果每列確實只有
VARCHAR
數據並且在轉換時不會有任何問題,那麼在執行此操作之前,有什麼簡單的方法可以確定NVARCHAR
?
該數據庫僅供美國使用,我認為任何列中都沒有任何外來字元或字母,所以我想研究一下……將其中許多列從 NVARCHAR 更改為 VARCHAR
在您繼續之前,您需要研究/確定這些列的實際業務需求。如果這些列中的一個或多個目前確實沒有包含任何不容易適應的字元
VARCHAR
,那並不意味著明天有人不會嘗試輸入純 Unicode 字元,這樣做會超出系統的預期設計。如果最終使用者/銷售人員/支持人員/文件認為僅 Unicode 字元可以被輸入到系統中,那麼系統需要允許這樣做,即使還沒有人使用該功能。如果是這種情況並且您認為應該更改它,因為您認為不需要輸入這些字元,那麼您需要將其送出給經理/產品負責人/等。此外,僅僅因為預期的使用者群在美國並不意味著不會使用僅限 Unicode 的字元。至少在“名稱”列、“描述”列等中很容易出現各種重音字元,或者誰知道呢。您應該與產品負責人和/或團隊進行的討論應該圍繞這些列/數據點中的每一個的要求展開。
例如,我知道其中一些列中數據的最大長度僅為 30 個字元左右,因此 NVARCHAR(MAX) 似乎有點過頭了。
與上述關於這些列中應允許哪些類型的字元類似,您首先需要確定係統允許人們發送多少個字元。如果描述欄位在 UI 中的上限為 500 - 1000 個字元,並且程式碼的其他部分,甚至文件(總是可以希望的,對嗎?),同意,那麼絕對是的,
NVARCHAR(MAX)
這絕對是矯枉過正。但是,如果該列需要儲存超過 4000 個字元,而不是由 8 位程式碼頁表示,那麼NVARCHAR(MAX)
並不過分(儘管您可能需要考慮一種更好的設計,而不是將太多字元儲存在一個單一的桌子)。無論哪種方式,一個特定的最多只有 30 個字元的事實NVARCHAR(MAX)
專欄是提供給產品負責人/團隊的好資訊,以便可以就該專欄的命運做出更明智的決定。也許目前允許 1000 個字元但最大記錄長度為 30 - 50 的欄位應該更新為僅允許 75 - 100 個。但這需要協調一致。
NVARCHAR
綜上所述,如果您想確定//列NCHAR
中是否有任何字元NTEXT
無法轉換為VARCHAR
,則需要轉換為VARCHAR
使用_BIN2
用於該特定列的排序規則的變體。例如,如果特定列正在使用Albanian_100_CI_AS
,那麼您將指定Albanian_100_BIN2
用於測試。使用_BIN2
排序規則的原因是,非二進制排序規則只會找到程式碼頁中至少有一個字元根本沒有任何映射並因此轉換為的實例?
. 但是,非二進制排序規則不會擷取沒有直接映射到程式碼頁中的字元的實例,而是具有“最適合”映射的字元。例如,上標 2 字元 ,²
在程式碼頁 1252 中有直接映射,因此絕對沒有問題。另一方面,它在程式碼頁 1250 中沒有直接映射(由阿爾巴尼亞排序規則使用),但它確實具有將其轉換為正常2
. 非二進制排序規則的問題在於2
它將等於²
,因此它不會註冊為無法轉換為的行VARCHAR
。例如:SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE French_100_CI_AS); -- Code Page 1252 -- ² SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_CI_AS); -- Code Page 1250 -- 2 SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_CI_AS) WHERE N'²' <> CONVERT(NVARCHAR(MAX), CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_CI_AS)); -- (no rows returned) SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_BIN2) WHERE N'²' <> CONVERT(NVARCHAR(MAX), CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_BIN2)); -- 2
理想情況下,您會顯式轉換回 to 以
NVARCHAR
明確程式碼在做什麼,儘管不這樣做仍會隱式轉換回NVARCHAR
,因此無論哪種方式,行為都是相同的。
我相信您正在尋找一個 select 語句,它會為您找到 ASCII (VARCHAR) 中不支持的字元串,對嗎?
下面引用的答案提供了這樣的聲明(帶有一些範例表結構)。該語句的作用是將您儲存為 NVARCHAR (Unicode) 的值與轉換為 VARCHAR (ASCII) 的相同值進行比較。如果查詢沒有返回任何內容,則可以進行轉換。如果一行包含任何值與儲存為 VARCHAR 不同的列,則將返回該列。
我從下面的另一個答案中複製了範例:
SELECT NAME, ADDRESS, DESCRIPTION FROM DBO.USERS WHERE NAME != CAST(NAME AS VARCHAR(4000)) OR ADDRESS != CAST(ADDRESS AS VARCHAR(4000)) OR DESCRIPTION != CAST(DESCRIPTION AS VARCHAR(4000))