簡體   English   中英

SQL 服務器 SQL_Latin1_General_CP1_CI_AS 可以安全地轉換為 Latin1_General_CI_AS 嗎?

[英]Can SQL Server SQL_Latin1_General_CP1_CI_AS be safely converted to Latin1_General_CI_AS?

我們有一個舊數據庫,其中一些(舊)列使用“SQL_Latin1_General_CP1_CI_AS”,最近的更改使用了“Latin1_General_CI_AS”。

這很痛苦,因為連接需要額外的 COLLATE 語句才能工作。

我想把一切都提升到“Latin1_General_CI_AS”。 據我所知,它們或多或少是相同的排序規則,在此過程中我不會丟失數據......

有誰知道是否是這種情況?

這是一個更完整的答案:

https://www.olcot.co.uk/revised-difference-between-collation-sql_latin1_general_cp1_ci_as-and-latin1_general_ci_as/

這些排序規則之間的主要區別在於它們如何應用字符擴展規則。 某些拉丁字符可能會擴展為多個字符。 SQL_xxxx 排序規則在處理非 unicode 文本時可能會忽略這些字符擴展,但將它們應用於 unicode 文本。 因此:當使用一種排序規則與另一種排序規則時,連接、排序和比較可能會返回不同的結果。

例子:

Latin1_General_CI_AS下,這兩個語句返回相同的記錄集,因為ß擴展為ss

SELECT * FROM MyTable3 WHERE Comments = 'strasse'
SELECT * FROM MyTable3 WHERE Comments = 'straße'

使用SQL_Latin1_General_CP1_CI_AS時,上述語句返回不同的記錄,因為ß被視為與ss不同的字符。

如果您要更改數據庫的排序規則,那么您肯定應該知道一些事情,以便您可以做出相應的計划:

  • 關於數據丟失的可能性:

    • NVARCHAR字段都是 Unicode,這是單個字符集,因此這些字段不會有任何數據丟失(這也包括 XML 字段,它們也存儲為 UTF-16 Little Endian)。 存儲 object / 列 / 索引 / 等名稱的元數據字段都是NVARCHAR ,因此無需擔心這些。
    • VARCHAR字段具有不同的排序規則但不同排序規則之間的相同代碼頁不會成為問題,因為代碼頁是字符集。
    • 如果正在使用的任何字符未在新代碼頁中表示,則具有不同排序規則並移動到不同代碼頁(更改排序規則時)的VARCHAR字段可能會丟失數據。 但是,這只是在物理更改特定字段的排序規則時出現的問題(如下所述),並且不會在更改數據庫的默認排序規則時發生。
  • 局部變量和字符串文字從數據庫默認值中獲取它們的排序規則。 更改數據庫默認值將更改用於局部變量和字符串文字的排序規則。 但是更改數據庫的默認排序規則不會更改用於該數據庫表中現有字符串列的排序規則。 在將列與文字和/或變量進行比較或連接時,這通常不會導致任何問題,因為由於排序優先級,文字和變量將采用列的排序規則。 唯一的潛在問題是代碼頁轉換可能發生在列的排序規則使用的代碼頁中不可用的值介於 128 - 255 之間的字符。

  • 如果您期望謂詞/比較/排序/連接/等在更改數據庫的默認排序規則時使列的行為有所不同,那么您需要使用以下命令顯式更改該列的排序規則:

     ALTER TABLE [{table_name}] ALTER COLUMN [{column_name}] {same_datatype} {same_NULL_or_NOT NULL_setting} COLLATE {name_of_Database_default_Collation};

    請務必指定當前正在使用的完全相同的數據類型和NULL / NOT NULL設置,否則如果還不是默認值,它們可以恢復為默認值。 之后,如果任何字符串列上的任何索引剛剛更改了其排序規則,那么您需要重建這些索引。

  • 更改數據庫的默認排序規則將更改某些特定於數據庫的元數據的排序規則,例如sys.objectssys.columnssys.indexes等中的name字段。根據局部變量或字符串文字過濾這些系統視圖獲勝這不是問題,因為雙方的排序規則都會發生變化。 但是,如果您將任何本地系統視圖加入到字符串字段上的臨時表中,並且本地數據庫和tempdb之間的數據庫級排序規則不匹配,那么您將收到“排序規則不匹配”錯誤。 這與補救措施一起在下面討論。

  • 這兩個排序規則之間的一個區別在於它們如何對VARCHAR數據的某些字符進行排序(這不會影響NVARCHAR數據)。 非 EBCDIC SQL_排序規則對VARCHAR數據使用所謂的“字符串排序”,而所有其他排序規則,甚至是用於非 EBCDIC SQL_排序規則的NVARCHAR數據,都使用所謂的“字排序”。 不同之處在於,在“單詞排序”中,破折號-和撇號' (可能還有一些其他字符?)的權重非常低,除非字符串中沒有其他差異,否則基本上會被忽略。 要查看此行為的實際效果,請運行以下命令:

     DECLARE @Test TABLE (Col1 VARCHAR(10) NOT NULL); INSERT INTO @Test VALUES ('aa'); INSERT INTO @Test VALUES ('ac'); INSERT INTO @Test VALUES ('ah'); INSERT INTO @Test VALUES ('am'); INSERT INTO @Test VALUES ('aka'); INSERT INTO @Test VALUES ('akc'); INSERT INTO @Test VALUES ('ar'); INSERT INTO @Test VALUES ('a-f'); INSERT INTO @Test VALUES ('a_e'); INSERT INTO @Test VALUES ('a''kb'); SELECT * FROM @Test ORDER BY [Col1] COLLATE SQL_Latin1_General_CP1_CI_AS; -- "String Sort" puts all punctuation ahead of letters SELECT * FROM @Test ORDER BY [Col1] COLLATE Latin1_General_100_CI_AS; -- "Word Sort" mostly ignores dash and apostrophe

    回報:

     String Sort ----------- a'kb af a_e aa ac ah aka akc am ar

    和:

     Word Sort --------- a_e aa ac af ah aka a'kb akc am ar

    雖然您將“丟失”“字符串排序”行為,但我不確定是否將其稱為“功能”。 這是一種被認為不受歡迎的行為(事實證明,它沒有被帶到任何 Windows 歸類中)。 但是,這兩個歸類之間的行為存在明顯差異(同樣,僅針對非 EBCDIC VARCHAR數據),並且您可能具有基於“字符串排序”行為的代碼和/或客戶期望。 這需要測試您的代碼,並可能研究這種行為變化是否會對用戶產生負面影響。

  • SQL_Latin1_General_CP1_CI_ASLatin1_General_100_CI_AS之間的另一個區別是能夠對VARCHAR數據進行擴展(對於大多數SQL_排序規則, NVARCHAR數據已經可以做到這些),例如將æ當作ae處理:

     IF ('æ' COLLATE SQL_Latin1_General_CP1_CI_AS = 'ae' COLLATE SQL_Latin1_General_CP1_CI_AS) BEGIN PRINT 'SQL_Latin1_General_CP1_CI_AS'; END; IF ('æ' COLLATE Latin1_General_100_CI_AS = 'ae' COLLATE Latin1_General_100_CI_AS) BEGIN PRINT 'Latin1_General_100_CI_AS'; END;

    回報:

     Latin1_General_100_CI_AS

    您在這里“失去”的唯一一件事就是無法進行這些擴展。 一般來說,這是遷移到 Windows 排序規則的另一個好處。 但是,就像從“字符串排序”到“單詞排序”的移動一樣,同樣需要注意:這兩個排序規則之間的行為存在明顯差異(同樣,僅針對VARCHAR數據),並且您可能有代碼和/或基於沒有這些映射的客戶期望。 這需要測試您的代碼,並可能研究這種行為變化是否會對用戶產生負面影響。

    (首先在@Zarepheth 的回答中提到並在此處擴展)

  • 另一個區別(這也是移動到 Windows 排序規則的好處)是過濾在NVARCHAR文字/變量/列上索引的VARCHAR列,您將不再使VARCHAR列上的索引無效。 這是由於 Windows 排序規則對VARCHARNVARCHAR數據使用相同的 Unicode 排序和比較規則。 因為這兩種類型的排序順序相同,所以當VARCHAR數據轉換為NVARCHAR時(顯式或隱式由於數據類型優先級),索引中的項目順序仍然有效。 有關此行為的更多詳細信息,請參閱我的帖子: 混合 VARCHAR 和 NVARCHAR 類型時對索引的影響

  • 服務器級 Collation 用於設置系統數據庫的 Collation,其中包括[model] [model]數據庫用作創建新數據庫的模板,其中包括每次服務器啟動時的[tempdb] 因此,如果數據庫的默認排序規則與實例的默認排序規則不匹配,並且您將本地表連接到字符串字段上的臨時表,那么您將收到排序規則不匹配錯誤。 幸運的是,有一種簡單的方法可以糾正執行CREATE #TempTable時“當前”的數據庫與[tempdb]之間的排序規則差異。 創建臨時表時,使用COLLATE子句聲明排序規則(在字符串列上)並使用特定排序規則(如果您知道數據庫將始終使用該排序規則)或DATABASE_DEFAULT (如果您不總是知道排序規則執行此代碼的數據庫):

     CREATE TABLE #Temp (Col1 NVARCHAR(40) COLLATE DATABASE_DEFAULT);

    這對於表變量不是必需的,因為它們從“當前”數據庫中獲取默認排序規則。 但是,如果您同時擁有表變量和臨時表並將它們連接到字符串字段,那么您將需要使用COLLATE {specific_collation}COLLATE DATABASE_DEFAULT ,如上所示。

  • 服務器級排序規則還控制局部變量名稱、 CURSOR變量名稱和GOTO標簽。 雖然這些都不會受到本問題中處理的具體變化的影響,但至少需要注意這一點。

  • 如果有多個版本可用,最好使用所需排序規則的最新版本。 從 SQL Server 2005 開始,引入了“90”系列排序規則,SQL Server 2008 引入了“100”系列排序規則。 您可以使用以下查詢找到這些排序規則:

     SELECT * FROM sys.fn_helpcollations() WHERE [name] LIKE N'%[_]90[_]%'; -- 476 SELECT * FROM sys.fn_helpcollations() WHERE [name] LIKE N'%[_]100[_]%'; -- 2686
  • 另外,雖然問題是關於不區分大小寫的排序規則,但應該注意的是,如果其他人希望進行類似的更改但使用區分大小寫的排序規則,那么 SQL 服務器排序規則和 Windows 排序規則之間的另一個區別,僅適用於VARCHAR數據, 是哪種情況先排序。 這意味着,如果您同時擁有Aa ,則SQL_排序規則將A排序在a之前,而非SQL_排序規則(以及處理NVARCHAR數據時的SQL_排序規則)將a排序在A之前。

有關更改數據庫或整個實例的排序規則的更多信息和詳細信息,請參閱我的帖子:
更改所有用戶數據庫中的實例、數據庫和所有列的排序規則:Go 可能有什么錯誤?

有關使用字符串和排序規則的更多信息,請訪問:排序規則信息

此 MSDN 論壇上有更多信息:

http://social.msdn.microsoft.com/Forums/en-US/sqlgetstarted/thread/196b4586-1338-434d-ba8c-49fa3c9bdeeb/

其中指出:

如果排序規則是 SQL_Latin1_General_CP1_CI_AS 或 Latin1_General_CI_AS,您應該會發現差別不大,但兩者都有比另一個更快或更慢的實例。

Latin1_General_CI_AS:- Latin1-General,不區分大小寫,區分重音,不區分假名,不區分寬度

SQL_Latin1_General_CP1_CI_AS:- 對於 Unicode 數據,SQL 代碼頁數據 1252 上的服務器排序順序 52

因此,我認為您不應該看到差異,特別是如果您的數據只是 a-z0-9

SELECT * FROM ::fn_helpcollations()
WHERE name IN (
'SQL_Latin1_General_CP1_CI_AS',
'Latin1_General_CI_AS'
)

...給...

Latin1_General_CI_AS:Latin1-General、不區分大小寫、區分重音、不區分假名、不區分寬度

SQL_Latin1_General_CP1_CI_AS:Latin1-General、不區分大小寫、區分重音、不區分假名、不區分寬度,適用於 Unicode 數據、SQL 非 Unicode 數據的代碼頁 1252 上的服務器排序順序 52

因此,據此,我會推斷所使用的代碼頁是相同的(Latin1-General => 1252),因此您應該不會遇到數據丟失 - 如果有任何內容要在轉換后更改,它可能是排序順序 - 這是可能無關緊要。

要做到這一點 go 到您的數據庫和 select 選項的屬性。

然后將集合類型更改為 SQL_Latin1_General_CP1_CS_AS。

在此處輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM