web-dev-qa-db-ja.com

UNIONでのCOLLATEの使用

COLLATEUNIONを併用するには2つのテーブルを結合したい(両方に同じ列と同じ型がある:varchar,int, int, decimal)。

次のエラーが発生しました:

sg 468、レベル16、状態9、行1 UNION操作での「Serbian_Latin_100_CI_AS」と「Croatian_CI_AS」の間の照合の競合を解決できません。

私のSQLステートメント:

select * from #IA_BIH
union 
select * from #IA_MNE  

どこに挿入するべきですかcollate database_default?さまざまな組み合わせを試しましたが、うまくいきませんでした。

6
Anja

照合名に基づいて、Microsoft SQL Serverを使用していると想定しています。

COLLATEは、データベースレベルまたは列レベルで使用できます。 2つのテーブルを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

もちろん、照合が競合する列がいくつかある場合は、それらの照合も定義する必要があります。

5
RLF

照合は、特にVARCHARデータの場合、少しトリッキーになる可能性があります。 NVARCHARデータとVARCHARデータの両方について、照合順序は並べ替えと比較のルールを制御します。ただし、VARCHARデータの場合、照合順序は文字セット(つまり、各8ビット値が表す文字を決定するために使用されるコードページ)も制御します。したがって、VARCHAR data canの照合順序を変更すると、データが失われます。

_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   ?
_

ただし、照合順序の不一致があるため、そのうちの1つを変更する必要があります。この特定のケースでは_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');
_

この時点で、これらの2つのうち1つを選択して、もう1つを強制的に同じにする必要があります。両方の照合順序が同じコードページを使用するため、選択は使用されている文字セットに影響しません。考慮する必要がある唯一の違いは、セルビア語とクロアチア語の並べ替えと比較のルールです。エンドユーザーの期待に最も近いものを選択してください。

1つのオプションは、@ RLFの回答に示されているように、SELECTステートメントで照合を強制することです。ここでの欠点は、_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. UNIONクエリで_SELECT *_を使用します。
  2. 各テーブルにCOLLATEオプションを追加する必要なく、これらのテーブルに対していくつかのクエリを実行します。

また、_CREATE TABLE_または_SELECT INTO_が実行されているデータベースのデフォルトの照合順序が、エラーメッセージに示されている2つの照合順序の1つであると想定すると、先に進んで_COLLATE database_default_。

2
Solomon Rutzky