Sql-Server

將 COLLATE 與 UNION 一起使用

  • December 30, 2016

怎麼COLLATEUNION?我想合併 2 個表(都有相同的列和相同的類型:)varchar,int, int, decimal

我收到以下錯誤:

sg 468, Level 16, State 9, Line 1 無法解決 UNION 操作中“Serbian_Latin_100_CI_AS”和“Croatian_CI_AS”之間的排序規則衝突。

我的 SQL 語句:

select * from #IA_BIH
union 
select * from #IA_MNE  

我應該在哪裡插入collate database_default?我嘗試了不同的組合,但沒有奏效。

根據排序規則名稱,我假設您使用的是 Microsoft SQL Server。

COLLATE 可以在數據庫級別或列級別使用。由於您正在嘗試 UNION 兩個表,因此在所需列上使用列排序規則將解決您的查詢。

這是一個範常式式碼,可以幫助您:

use testdb
GO
CREATE TABLE dbo.Serbian  (Name VARCHAR(20) COLLATE Serbian_Latin_100_CI_AS);
CREATE TABLE dbo.Croatian (Name VARCHAR(20) COLLATE  Croatian_CI_AS);
GO
INSERT INTO dbo.Serbian VALUES ('serbian');
INSERT INTO dbo.Croatian VALUES ('croation');
GO

-- Collate to a particular named collation
SELECT Name COLLATE Serbian_Latin_100_CI_AS as CollatedNameSerbian from dbo.Serbian 
UNION ALL
SELECT Name COLLATE Serbian_Latin_100_CI_AS from dbo.Croatian 
GO
-- Collate to the database default collation
SELECT Name  COLLATE database_default as CollatedNameDBDefault from dbo.Serbian 
UNION ALL
SELECT Name COLLATE database_default from dbo.Croatian 
GO

DROP TABLE dbo.Serbian;
DROP TABLE dbo.Croatian;
GO

當然,如果您有多個列的排序規則衝突,您還需要定義它們的排序規則。

排序規則可能有點棘手,尤其是對於VARCHAR數據。對於NVARCHARVARCHAR數據,排序規則控制排序和比較規則。但是對於VARCHAR數據,排序規則還控製字元集(即使用哪個程式碼頁來確定每個 8 位值代表什麼字元)。VARCHAR因此,更改數據的排序規則可能會導致數據失去:

SELECT CHAR(230) AS [DB-Collation],
      CHAR(230) COLLATE Korean_100_CI_AS AS [Korean],
      CHAR(230) COLLATE Albanian_CI_AS AS [Albanian],
      CHAR(230) COLLATE Greek_100_CI_AS AS [Greek];
-- æ            a   ?

但是,由於您的排序規則不匹配,因此您需要更改其中之一。我建議不要database_default在這種特殊情況下使用,因為這將與正在執行查詢的數據庫相關,這可能會導致行為不一致。

幸運的是,錯誤中提到的兩個排序規則具有相同的程式碼頁:1250。您可以使用以下查詢找到此資訊:

SELECT col.[name], COLLATIONPROPERTY(col.[name], 'CodePage') AS [CodePage]
FROM   sys.fn_helpcollations() col
WHERE  [name] IN (N'Serbian_Latin_100_CI_AS', N'Croatian_CI_AS');

此時,您需要從這兩個中選擇一個來強制另一個相同。因為兩個排序規則使用相同的程式碼頁,所以選擇不會影響正在使用的字元集。您需要關注的唯一區別是塞爾維亞語和克羅地亞語之間的排序和比較規則;選擇最符合最終使用者期望的那個。

一種選擇是在SELECT聲明中強制執行排序規則,因為您正在嘗試執行此操作,如@RLF 的回答所示。這裡的缺點是您不能再使用SELECT *(如果這是儲存過程中的程式碼,最好還是不要使用SELECT *)。

另一種選擇是在創建臨時表時強制其中一個表的排序規則,無論是使用CREATE TABLE或完成SELECT INTO

SELECT ac.*
FROM   sys.all_columns ac
WHERE  ac.[object_id] = OBJECT_ID(N'sys.objects')
AND    ac.[name] = N'name';
-- SQL_Latin1_General_CP1_CI_AS (on my system, at least)

SELECT [name] COLLATE Hebrew_100_CI_AS AS [name]
INTO   #coltest
FROM   sys.objects;

SELECT sc.*
FROM   [tempdb].sys.columns sc
WHERE  sc.[object_id] = OBJECT_ID(N'tempdb..#coltest');
-- Hebrew_100_CI_AS

這樣做的好處是您可以:

  1. SELECT *在您的UNION查詢中使用。
  2. 對這些表執行多個查詢,而無需COLLATE為每個表添加選項。

並且,假設正在執行CREATE TABLEor的數據庫的預設排序規則SELECT INTO是錯誤消息中指出的兩個排序規則之一,那麼您可以繼續使用COLLATE database_default.

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