等しい操作で「SQL_Latin1_General_CP1_CI_AS」と「Latin1_General_CI_AS」の間の照合の競合を解決できません


341

次のコードがあります

SELECT tA.FieldName As [Field Name],
       COALESCE(tO_A.[desc], tO_B.[desc], tO_C.Name, tA.OldVAlue) AS [Old Value],
       COALESCE(tN_A.[desc], tN_B.[desc], tN_C.Name, tA.NewValue) AS [New Value],
       U.UserName AS [User Name],
       CONVERT(varchar, tA.ChangeDate) AS [Change Date] 
  FROM D tA
       JOIN 
       [DRTS].[dbo].[User] U 
         ON tA.UserID = U.UserID
       LEFT JOIN 
       A tO_A 
         on tA.FieldName = 'AID' 
        AND tA.oldValue = CONVERT(VARCHAR, tO_A.ID)
       LEFT JOIN 
       A tN_A 
         on tA.FieldName = 'AID' 
        AND tA.newValue = CONVERT(VARCHAR, tN_A.ID)
       LEFT JOIN 
       B tO_B 
         on tA.FieldName = 'BID' 
        AND tA.oldValue = CONVERT(VARCHAR, tO_B.ID)
       LEFT JOIN 
       B tN_B 
         on tA.FieldName = 'BID' 
        AND tA.newValue = CONVERT(VARCHAR, tN_B.ID)
       LEFT JOIN 
       C tO_C 
         on tA.FieldName = 'CID' 
        AND tA.oldValue = tO_C.Name
       LEFT JOIN 
       C tN_C 
         on tA.FieldName = 'CID' 
        AND tA.newValue = tN_C.Name
 WHERE U.Fullname = @SearchTerm
ORDER BY tA.ChangeDate

コードを実行すると、テーブルCに2つの結合を追加した後、エラーがタイトルに貼り付けられます。これは、SQL Server 2008を使用していて、このdbのコピーを私のマシンは2005年です。

回答:


306

テーブルに2つの異なる照合順序の不一致があります。次のクエリを使用して、テーブルの各列の照合順序を確認できます。

SELECT
    col.name, col.collation_name
FROM 
    sys.columns col
WHERE
    object_id = OBJECT_ID('YourTableName')

照合順序は、文字列を並べ替えて比較するときに必要であり、使用されます。一般に、データベース全体で単一の一意の照合順序を使用することをお勧めします。単一のテーブルまたはデータベース内で異なる照合順序を使用しないでください。問題があるだけです。

1つの照合順序で解決したら、次のコマンドを使用して、まだ一致していないテーブル/列を変更できます。

ALTER TABLE YourTableName
  ALTER COLUMN OffendingColumn
    VARCHAR(100) COLLATE Latin1_General_CI_AS NOT NULL

マーク

更新:データベース内のフルテキストインデックスを見つけるには、次のクエリを使用します。

SELECT
    fti.object_Id,
    OBJECT_NAME(fti.object_id) 'Fulltext index',
    fti.is_enabled,
    i.name 'Index name',
    OBJECT_NAME(i.object_id) 'Table name'
FROM 
    sys.fulltext_indexes fti
INNER JOIN 
    sys.indexes i ON fti.unique_index_id = i.index_id

次に、以下を使用してフルテキストインデックスを削除できます。

DROP FULLTEXT INDEX ON (tablename)

私が探していたものとまったく同じタイプのmarcに感謝します。テーブルの1つがなんらかの理由で照合順序が異なりました。標準の照合に変更して、何が起こるかを見てみましょう。
jhowe

marcこれを取得しています:全文検索が有効になっているため、列を変更またはドロップできません。
jhowe

1
その場合は、そのテーブルのフルテキストインデックスを一時的に削除し、照合順序を変更してから、フルテキストインデックスを再作成する必要があります
marc_s

1
OPのおかげで、これが役立つように一時テーブルを設定していましたが、テーブルを変更できなかったため、(次のように)開始するために正しく宣言する必要がありました:DECLARE @Table TABLE(CompareMessage VARCHAR(50)COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL)
FrostbiteXIII

1
同じテーブルに2つの異なる照合があるのはなぜですか。英語の名前だけを必要とするnvarcharとして1つの列があり、ロシア語の文字として他の列が必要な場合、他の列は日本語の文字として必要です。これはどのように整理すればよいですか?これらすべてをカバーする単一の照合はありますか?
batmaci 2017年

854

私は次のことを行います:

...WHERE 
    fieldname COLLATE DATABASE_DEFAULT = otherfieldname COLLATE DATABASE_DEFAULT

毎回動作します。:)


68
これは、SOで最も有用な投稿の1つです
Jamie Strauss、

2
同じデータベースを使用して2つのレガシーシステムを使用していたため、テーブルの照合順序を変更すると機能が破損するかどうか確信が持てなかったため、このソリューションを使用しました。
paolobueno 2014年

5
同じ2つのフィールドが他の場所(比較、共用体、合体など)で一緒に使用されている場合は、それらのそれぞれにも照合順序が指定されていることを確認してください。
ザレフェス2014

5
これは非常に便利です。ローカルデータベースを使用し、リンクサーバーに対してクエリを実行していますが、照合順序が2つあります。明らかに、リンクサーバーで照合順序を変更することはできません。また、ローカルで自分の鉱山を変更したくなかったので、これが絶対に最善の答えです。
jtate 2014年

7
@ppumkin優れたソリューションですが、問題を解決するのではなく、回避するだけです。各クエリの照合順序を変更する必要がない限り、これは面倒で最適なパフォーマンスが得られません。それは素晴らしい答えですが、私が感じる受け入れられた答えはより良いものです。
ロブ

80

使用 collateクエリで句をます。

LEFT JOIN C tO_C on tA.FieldName = 'CID' AND tA.oldValue COLLATE Latin1_General_CI_AS = tO_C.Name  

構文が正確ではない場合がありますが(BOLを確認してください)、クエリの照合をオンザフライで変更できます。結合ごとに句を追加する必要がある場合があります。

編集:これは正しくないことに気づきました。collat​​e句は、変更する必要があるフィールドの後にありtA.oldValueます。この例では、フィールドの照合順序を変更しました。


29

このエラーがスローされているフィールドを特定し、以下を追加します。COLLATE DATABASE_DEFAULT

コードフィールドに結合された2つのテーブルがあります。

...
and table1.Code = table2.Code
...

クエリを次のように更新します。

...
and table1.Code COLLATE DATABASE_DEFAULT = table2.Code COLLATE DATABASE_DEFAULT
...

ありがとう。製品データベースで作業しているとき、受け入れられた回答で示唆されているように、データベース構造を常に変更できるとは限りません。
ジェニファーウッド

20

これは、2つの異なるデータベース、特に2つの異なるサーバーからの2つの異なるデータベースがある場合に簡単に発生します。最良のオプションは、それを共通のコレクションに変更して、結合または比較を行うことです。

SELECT 
   *
FROM sd
INNER JOIN pd ON sd.SCaseflowID COLLATE Latin1_General_CS_AS = pd.PDebt_code COLLATE Latin1_General_CS_AS

13

@ヴァルキリー素晴らしい答え。ストアドプロシージャ内でサブクエリを使用して同じことを実行する場合、ここでケースを入れたと思います。このケースであなたの答えが機能するかどうか疑問に思ったのですが、それは素晴らしいことでした。

...WHERE fieldname COLLATE DATABASE_DEFAULT in (
          SELECT DISTINCT otherfieldname COLLATE DATABASE_DEFAULT
          FROM ...
          WHERE ...
        )


6

根本的な原因は、スキーマを取得したSQLサーバーデータベースの照合順序がローカルインストールとは異なることです。照合順序を気にしたくない場合は、SQL Server 2008データベースと同じ照合順序を使用してSQL Serverをローカルに再インストールします。


同じ問題があった場合、最初にサーバーとデータベースのプロパティをチェックして、それらの照合順序が同じかどうかを確認する必要があります
madan

5

エラー(...の照合の競合を解決できない)は通常、複数のデータベースのデータを比較しているときに発生します。

現在、データベースの照合順序を変更できないため、COLLATE DATABASE_DEFAULTを使用してください。

----------
AND db1.tbl1.fiel1 COLLATE DATABASE_DEFAULT =db2.tbl2.field2 COLLATE DATABASE_DEFAULT 

これは、すでに与えられている別の回答と
同じ

4

私は以前にこのようなものを持っていました、そして私たちが見つけたのは2つのテーブル間の照合が異なるということでした。

これらが同じであることを確認してください。


4

marc_sの回答のおかげで、私は元の問題を解決しました-さらに一歩進んで、テーブル全体を一度に変換する1つのアプローチを投稿しました-alter columnステートメントを生成するtsqlスクリプト:

DECLARE @tableName VARCHAR(MAX)
SET @tableName = 'affiliate'
--EXEC sp_columns @tableName
SELECT  'Alter table ' + @tableName + ' alter column ' + col.name
        + CASE ( col.user_type_id )
            WHEN 231
            THEN ' nvarchar(' + CAST(col.max_length / 2 AS VARCHAR) + ') '
          END + 'collate Latin1_General_CI_AS ' + CASE ( col.is_nullable )
                                                    WHEN 0 THEN ' not null'
                                                    WHEN 1 THEN ' null'
                                                  END
FROM    sys.columns col
WHERE   object_id = OBJECT_ID(@tableName)

取得:ALTER TABLEアフィリエイトALTER COLUMN myTable NVARCHAR(4000)COLLATE Latin1_General_CI_AS NOT NULL

私はする必要当惑されることに認めるよcol.max_length / 2 -


長さは内部的にバイト数として保存されるため、2で除算する必要があると思います。Nvarcharは、1文字ではなく2バイトをvarcharとして受け取ります。
Zebi

素晴らしい仕事です。おそらくcol.max_length / 2が原因で、nchaデータ型のクエリ用量カウントがどれだけ上にあるか–
Imran

2

この問題の原因となっているデータベースのCREATE DATABASEスクリプトがある場合(私の場合と同様)、次のCREATEスクリプトを使用して照合を照合できます。

-- Create Case Sensitive Database
CREATE DATABASE CaseSensitiveDatabase
COLLATE SQL_Latin1_General_CP1_CS_AS -- or any collation you require
GO
USE CaseSensitiveDatabase
GO
SELECT *
FROM sys.types
GO
--rest of your script here

または

-- Create Case In-Sensitive Database
CREATE DATABASE CaseInSensitiveDatabase
COLLATE SQL_Latin1_General_CP1_CI_AS -- or any collation you require
GO
USE CaseInSensitiveDatabase
GO
SELECT *
FROM sys.types
GO
--rest of your script here

これにより、必要な照合がすべてのテーブルに適用されます。サーバー上のすべてのデータベースで照合順序を同じにしておくことが理想的です。お役に立てれば。

次のリンクに関する詳細情報:SQL SERVER –サーバーで異なる照合順序を使用したデータベースの作成


2

このサイトのコンテンツを使用して、すべてのテーブルのすべての列の照合順序を変更する次のスクリプトを作成しました。

CREATE PROCEDURE [dbo].[sz_pipeline001_collation] 
    -- Add the parameters for the stored procedure here
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;


SELECT 'ALTER TABLE [' + SYSOBJECTS.Name + '] ALTER COLUMN [' + SYSCOLUMNS.Name + '] ' +
SYSTYPES.name + 
    CASE systypes.NAME
    WHEN 'text' THEN ' '
    ELSE
    '(' + RTRIM(CASE SYSCOLUMNS.length
    WHEN -1 THEN 'MAX'
    ELSE CONVERT(CHAR,SYSCOLUMNS.length)
    END) + ') ' 
    END

    + ' ' + ' COLLATE Latin1_General_CI_AS ' + CASE ISNULLABLE WHEN 0 THEN 'NOT NULL' ELSE 'NULL' END
    FROM SYSCOLUMNS , SYSOBJECTS , SYSTYPES
    WHERE SYSCOLUMNS.ID = SYSOBJECTS.ID
    AND SYSOBJECTS.TYPE = 'U'
    AND SYSTYPES.Xtype = SYSCOLUMNS.xtype
    AND SYSCOLUMNS.COLLATION IS NOT NULL
    AND NOT ( sysobjects.NAME LIKE 'sys%' )
    AND NOT ( SYSTYPES.name LIKE 'sys%' )

END

1
nvarchar列のSYSCOLUMNS.lengthは2で除算する必要があります
palota

2

一致しない照合のレベル(サーバー、データベース、テーブル、列、文字)を確認します。

それがサーバーである場合、これらの手順は私を一度助けました:

  1. サーバーを停止します
  2. sqlservr.exeツールを見つける
  3. 次のコマンドを実行します。

    sqlservr -m -T4022 -T3659 -s"name_of_insance" -q "name_of_collation"

  4. SQLサーバーを起動します。

    net start name_of_instance

  5. サーバーの照合順序をもう一度確認してください。

詳細は次のとおりです。

https://www.mssqltips.com/sqlservertip/3519/changing-sql-server-collat​​ion-after-installation/


2

これがDB全体で発生する場合は、DB照合を次のように変更することをお勧めします。

USE master;  
GO  
ALTER DATABASE MyOptionsTest  
COLLATE << INSERT COLATION REQUIRED >> ;  
GO  

--Verify the collation setting.  
SELECT name, collation_name  
FROM sys.databases  
WHERE name = N'<< INSERT DATABASE NAME >>';  
GO 

参照はこちら


残念ながら、これにより既存のテーブルの照合順序は変更されませんが、新しいテーブルのデフォルトのみが変更されます
RockScience

2

varcharおよびvarchar(MAX)列を処理するために、@ JustSteveの回答にコードを追加しました。

DECLARE @tableName VARCHAR(MAX)
SET @tableName = 'first_notes'
--EXEC sp_columns @tableName
SELECT  'Alter table ' + @tableName + ' alter column ' + col.name
        + CASE ( col.user_type_id )
            WHEN 231
            THEN ' nvarchar(' + CAST(col.max_length / 2 AS VARCHAR) + ') '
            WHEN 167
            THEN ' varchar(' + CASE col.max_length 
                                WHEN -1 
                                THEN 'MAX'
                                ELSE 
                                CAST(col.max_length AS VARCHAR)
                                end
                                 + ') '
          END + 'collate Latin1_General_CI_AS ' + CASE ( col.is_nullable )
                                                    WHEN 0 THEN ' not null'
                                                    WHEN 1 THEN ' null'
                                                  END
FROM    sys.columns col
WHERE   object_id = OBJECT_ID(@tableName)


1

古いjdbcドライバーを使用すると、同様のエラーが発生しました(INTERSECT操作で「SQL_Latin1_General_CP1_CI_AS」と「SQL_Latin1_General_CP1250_CI_AS」の照合の競合を解決できません)。

MicrosoftまたはオープンソースプロジェクトjTDSから新しいドライバーをダウンロードすることで、これを解決しました


1

これが私たちがやったことです。この状況では、オンデマンドの日付制限を使用してアドホッククエリを実行する必要があり、クエリはテーブルで定義されています。

新しいクエリでは、異なるデータベース間でデータを照合し、両方のデータベースからのデータを含める必要があります。

iSeries / AS400システムからデータをインポートするデータベースとレポートデータベースの間でCOLLATIONが異なるようです-これは、特定のデータタイプ(名前のギリシャ語のアクセントなど)が原因である可能性があります。

したがって、以下の結合句を使用しました。

...LEFT Outer join ImportDB..C4CTP C4 on C4.C4CTP COLLATE Latin1_General_CS_AS=CUS_Type COLLATE Latin1_General_CS_AS

1

あなたは4つの簡単なステップを使用してこれを簡単に行うことができます

  1. 念のため、データベースをバックアップしてください
  2. データベースの照合順序の変更:データベースを右クリックしてプロパティを選択し、オプションに移動して、照合順序を必要な照合順序に変更します。
  3. すべてのデータベースオブジェクトを削除および再作成するスクリプトを生成します。データベースを右クリックし、タスクを選択して、スクリプトの生成を選択します(ウィザードの詳細オプションで[削除して作成]を選択し、[スキーマとデータ]も選択してください)。
  4. 上記で生成されたスクリプトを実行する

1
INSERT INTO eSSLSmartOfficeSource2.[dbo].DeviceLogs  (DeviceId,UserId,LogDate,UpdateFlag) 
SELECT DL1.DeviceId ,DL1.UserId COLLATE DATABASE_DEFAULT,DL1.LogDate 
,0 FROM eSSLSmartOffice.[dbo].DeviceLogs DL1 
WHERE  NOT EXISTS 
(SELECT DL2.DeviceId ,DL2.UserId COLLATE DATABASE_DEFAULT
,DL2.LogDate ,DL2.UpdateFlag 
FROM eSSLSmartOfficeSource2.[dbo].DeviceLogs DL2    
WHERE  DL1.DeviceId =DL2.DeviceId
 and DL1.UserId collate  Latin1_General_CS_AS=DL2.UserId collate  Latin1_General_CS_AS
  and DL1.LogDate =DL2.LogDate )

0

データベースに照合順序の問題はまったくないかもしれませんが、元の照合順序とは異なる照合順序でサーバーのバックアップからデータベースのコピーを復元し、コードが一時テーブルを作成している場合、これらの一時テーブルは照合順序を継承しますサーバーとデータベースとの競合が発生します。


0
ALTER DATABASE test2            --put your database name here
COLLATE Latin1_General_CS_AS    --replace with the collation you need

0

同様の要件がありました。同様のシナリオを持つ人のためにここに私のアプローチを文書化しています...

シナリオ

  • 正しい照合順序でクリーンインストールしたデータベースがあります。
  • 照合順序が間違っている別のデータベースがあります。
  • 前者で定義された照合を使用するには、後者を更新する必要があります。

解決

SQL Serverスキーマ比較(SQL Serverデータツール / Visual Studioから)を使用して、ソース(クリーンインストール)と宛先(無効な照合のあるDB)を比較します。

私の場合、2つのDBを直接比較しました。ただし、プロジェクトを介して作業し、その間に手動でピースを微調整できるようにすることもできます...

  • Visual Studioを実行する
  • 新しいSQL Serverデータプロジェクトを作成する
  • [ツール]、[SQL Server]、[新しいスキーマの比較]をクリックします
  • ソースデータベースを選択します
  • ターゲットデータベースを選択します
  • オプションをクリックします(⚙)
    • 以下の下でObject Typesあなたが興味を持っているだけで、それらの種類を選択します(私にとってはそれだけだったViewsTables
    • 下のGeneral選択:
      • データ損失の可能性をブロック
      • DDLトリガーの無効化と再有効化
      • 暗号化プロバイダーのファイルパスを無視する
      • ファイルとログファイルのパスを無視
      • ファイルサイズを無視する
      • ファイルグループの配置を無視する
      • フルテキストカタログファイルのパスを無視する
      • キーワードの大文字と小文字を区別しない
      • ログインSIDを無視する
      • 引用された識別子を無視する
      • ルートの有効期間を無視する
      • ステートメント間のセミコロンを無視する
      • 空白を無視
      • スクリプト更新モジュール
      • 新しい制約のスクリプト検証
      • 照合の互換性を確認する
      • 展開を確認す​​る
  • 比較をクリックします
    • 削除のフラグが付けられたオブジェクトのチェックをすべて外します(注:これらにはまだ照合の問題がある可能性があります。ただし、ソース/テンプレートデータベースで定義されていないため、不明です。どちらにしても、照合順序の変更のみを対象としています)。DELETEフォルダを右クリックしてを選択すると、一度にすべてのチェックを解除できますEXCLUDE
    • 同様に除外する CREATEオブジェクトをます(ここでは、オブジェクトがターゲットに存在しないため、そこに間違った照合順序を付けることはできません。存在する必要があるかどうかは、別のトピックの質問です)。
    • 変更の下の各オブジェクトをクリックして、そのオブジェクトのスクリプトを表示します。差分を使用して、照合順序のみを変更していることを確認します(手動で検出された他の違いはすべて、それらのオブジェクトを手動で除外/処理する必要があります)。
  • クリックUpdateして変更をプッシュ

これには、まだいくつかの手作業(たとえば、照合にのみ影響を与えていることの確認)が含まれますが、依存関係は処理されます。

また、有効なスキーマのデータベースプロジェクトを保持できるので、すべてのターゲットDBが同じスキーマになると想定して、更新するデータベースが1つ以上ある場合に、DBのユニバーサルテンプレートを使用できます。

データベースプロジェクトの設定を一括修正する場合は、データベースプロジェクトのファイルで検索/置換を使用することもできます(たとえば、スキーマ比較を使用して無効なデータベースからプロジェクトを作成し、プロジェクトファイルを修正してから、ソース/ターゲットを切り替えます)スキーマを比較して、変更をDBに戻します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.