在SQL Server中的字符類型都是有排序規則(collation)的,例如在下面的SQL語句中,我們建立了一個表變量@table_people,其中我們使用關鍵字COLLATE給列[Name]定義了排序規則"Chinese_PRC_CI_AS",也給列[Description]定義了排序規則"SQL_Latin1_General_CP1_CI_AS":
DECLARE @table_people TABLE ( [Name] NVARCHAR(50) COLLATE Chinese_PRC_CI_AS, [Description] NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS, [Age] INT ) INSERT INTO @table_people([Name],[Description],[Age]) VALUES (N'張三' COLLATE Chinese_PRC_CI_AS,N'這個人叫張三' COLLATE SQL_Latin1_General_CP1_CI_AS,31), (N'李四' COLLATE Chinese_PRC_CI_AS,N'這個人叫李四' COLLATE SQL_Latin1_General_CP1_CI_AS,32), (N'王五' COLLATE Chinese_PRC_CI_AS,N'這個人叫王五' COLLATE SQL_Latin1_General_CP1_CI_AS,33) SELECT * FROM @table_people
這段SQL代碼可以成功執行,因為我們使用了COLLATE關鍵字為每一個字符串指定了相應的排序規則。
但是,如果我們對不同排序規則的字符類型進行操作的時候就會報錯,如下所示:
DECLARE @table_people TABLE ( [Name] NVARCHAR(50) COLLATE Chinese_PRC_CI_AS, [Description] NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS, [Age] INT ) INSERT INTO @table_people([Name],[Description],[Age]) VALUES (N'張三' COLLATE Chinese_PRC_CI_AS,N'這個人叫張三' COLLATE SQL_Latin1_General_CP1_CI_AS,31), (N'李四' COLLATE Chinese_PRC_CI_AS,N'這個人叫李四' COLLATE SQL_Latin1_General_CP1_CI_AS,32), (N'王五' COLLATE Chinese_PRC_CI_AS,N'王五' COLLATE SQL_Latin1_General_CP1_CI_AS,33) SELECT * FROM @table_people WHERE [Name]=[Description]--Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Chinese_PRC_CI_AS" in the equal to operation.
上面的SQL語句,會在最后的SELECT語句報錯:
Msg 468, Level 16, State 9, Line 14
Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Chinese_PRC_CI_AS" in the equal to operation.
由於我們在SELECT語句的WHERE條件中比較了列[Name]和列[Description]的值,但是[Name]和[Description]是兩個排序規則不同的列,不能直接進行比較操作,所以我們要使用COLLATE關鍵字對排序規則進行轉換后,才能進行比較:
DECLARE @table_people TABLE ( [Name] NVARCHAR(50) COLLATE Chinese_PRC_CI_AS, [Description] NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS, [Age] INT ) INSERT INTO @table_people([Name],[Description],[Age]) VALUES (N'張三' COLLATE Chinese_PRC_CI_AS,N'這個人叫張三' COLLATE SQL_Latin1_General_CP1_CI_AS,31), (N'李四' COLLATE Chinese_PRC_CI_AS,N'這個人叫李四' COLLATE SQL_Latin1_General_CP1_CI_AS,32), (N'王五' COLLATE Chinese_PRC_CI_AS,N'王五' COLLATE SQL_Latin1_General_CP1_CI_AS,33) --將列[Description]的排序規則轉換為Chinese_PRC_CI_AS SELECT * FROM @table_people WHERE [Name]=[Description] COLLATE Chinese_PRC_CI_AS --將列[Name]的排序規則轉換為SQL_Latin1_General_CP1_CI_AS SELECT * FROM @table_people WHERE [Name] COLLATE SQL_Latin1_General_CP1_CI_AS=[Description]
由於現在我們使用COLLATE關鍵字對列[Name]和列[Description]的排序規則進行了轉換,保證了SELECT語句WHERE條件中等號兩邊字符類型的排序規則是相同的,所以現在兩個SELECT語句都不會報錯,並成功返回了查詢結果。
前面我們說了,COLLATE關鍵字可以指定SQL Server中字符類型的排序規則,它可以作用於char、varchar、text、nchar、nvarchar、ntext數據類型。
當我們在操作臨時表中的字符類型時,就很有可能需要使用COLLATE關鍵字對排序規則進行轉換,因為SQL Server中的臨時表存在於系統數據庫tempdb中,而系統數據庫tempdb的排序規則很有可能和用戶創建數據庫的排序規則不同,所以如果我們在用戶創建的數據庫中使用了臨時表,並對字符類型進行了操作,那么很有可能會因為系統數據庫tempdb的排序規則和用戶創建數據庫不一致而報錯,這時候我們就需要使用COLLATE關鍵字對不同排序規則的字符類型進行轉換,這是一個比較常用的使用場景。另外在用戶創建的數據庫中使用表變量一般不會存在排序規則的問題,原因如下:
The collations for the string type (char, nchar, varchar, nvarchar) columns, if not given explicitly, will take
the database collation of TempDB in a temp table, and inherit the collation of the current user database in a table variable. If not handled correctly, string comparing will fail.
參考: Local Temporary Tables and Table Variables
我們還可以在COLLATE關鍵字后使用database_default,指定字符類型的排序規則為當前數據庫使用的排序規則:
DECLARE @table_people TABLE ( [Name] NVARCHAR(50) COLLATE database_default, [Description] NVARCHAR(50) COLLATE database_default, [Age] INT ) INSERT INTO @table_people([Name],[Description],[Age]) VALUES (N'張三' COLLATE database_default,N'這個人叫張三' COLLATE database_default,31), (N'李四' COLLATE database_default,N'這個人叫李四' COLLATE database_default,32), (N'王五' COLLATE database_default,N'王五' COLLATE database_default,33) SELECT * FROM @table_people WHERE [Name]=[Description]
可以參考下面的微軟文檔,對COLLATE關鍵字進行詳細的了解:
Windows Collation Name (Transact-SQL)
SQL Server Collation Name (Transact-SQL)