照合順序の問題
まず、照合順序についておさらいしておきましょう。照合順序とは、簡潔に言うと文字の並び替え規則、比較規則を指定できる機能です。例えば大文字のAと小文字のaを比較する際に同じものとみなすのか、それとも異なるものとみなすのかといったようなことや、アクセント符号の有無を区別するかどうか (例えばëとeを区別するかどうか) といったことを指定できます。
Containedでない通常のデータベースでは、テーブルや関数などのオブジェクトを作成すると、特に何も指定しない限り作成先のデータベースの照合順序が適用されます。例えば照合順序がSQL_Latin1_General_CP1_CI_ASのデータベースに新しくテーブルを作成すると、そのカラムの照合順序も SQL_Latin1_General_CP1_CI_ASになります。
この原則は単純で良いのですが、作成されるオブジェクトの照合順序が作成先のデータベースに依存しているという点で、問題が生じる事があります。 例えば、データベースの照合順序がSQL_Latin1_General_CP1_CS_AS、インスタンスの照合順序がSQL_Latin1_General_CP1_CI_ASという環境で、一時テーブルを使用する以下のクエリを実行してみてください (2つの照合順序の違いは大文字小文字を区別するかどうかだけです)。クエリはエラーになります。
CREATE TABLE T1 (T1_txt nvarchar(max)) ; GO CREATE TABLE #T2 (T2_txt nvarchar(max)); GO SELECT T1_txt, T2_txt FROM T1 JOIN #T2 ON T1.T1_txt = #T2.T2_txt ; 実行結果 Msg 468, Level 16, State 9, Line 4 Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "SQL_Latin1_General_CP1_CS_AS" in the equal to operation.
エラーの内容は「結合条件で指定している各カラムの照合順序が異なるため、= (イコール) 操作を解決できない」というものです。片方のカラムでは大文字小文字を区別しないで比較するという設定であるにもかかわらず、もう一方のカラムでは大文字小文字を区別して比較するという照合順序が指定されているため、SQL Server は = 操作を実行できないのです。
照合順序が異なってしまうのは、一時テーブルがシステム データベースのtempdbに作成されるため、tempdbの照合順序が一時テーブルのカラムの照合順序に適用されてしまうからです。
tempdbの照合順序は基本的にインスタンスの照合順序が適用されるため、カラムT2_txtの照合順序は SQL_Latin1_General_CP1_CI_AS になります。しかし、もしインスタンスの設定が SQL_Latin1_General_CP1_CS_ASの環境であれば、カラム T2_txt の照合順序はSQL_Latin1_General_CP1_CS_AS ですから、 T1_txt の照合順序と一致し、クエリは正常に実行されていたでしょう。つまり、このクエリはインスタンスの設定によってエラーとなるか正常に実行されるかが左右されるクエリなのです。
また、日本語以外の照合順序では、少し変わった問題が発生することがあります。以下の関数を見てください。
CREATE FUNCTION f() RETURNS INT AS BEGIN DECLARE @I INT = 1 DECLARE @İ INT = 2 RETURN 1 * @i END;
この関数では、大文字と小文字を区別する照合順序 (case-sensitive) であれば@iがどの変数にもバインドできずにエラーとなりますが、インスタンスの照合順序が大文字区別を区別せず、アクセントを区別する Latin1_General の場合、@iは@Iとバインドすることができるので 1 が結果として得られます。しかし、インスタンスの照合順序が大文字小文字を区別しないTurkishの場合@iは@İとバインドするので2が結果として得られることになるのです。つまり、インスタンスの照合順序の違いによって、変数@iがどの変数にバインドされるかが変わってしまうのです。