3

私は数年前から MS SQL を扱っていますが、前職ではこのようなことは一度もありませんでした。しかし、私が今働いている場所では、原因を知りたいエラーが発生しました。

私はストアド プロシージャを作成し、いくつかのパラメーターを使用して Delphi 5 (そうです) アプリで呼び出しました。これは、2 つのデータベース (異なる時間からのコピー) で正常に機能しました。しかし、別のDB(再びコピー)で試してみましたが、次のエラーが発生しました:

Cannot resolve the collation conflict between "Latin1_General_CI_AS" and 
"SQL_Latin1_General_CP1_CI_AS" in the equal to operation.

これは、一時テーブルを作成してからデータを挿入しようとすることで得られました。私も加入していません。そして面白いことに、WHERE 句全体を削除すると、機能します。そのままにしておくと (パラメーターを 1 つのテーブルと比較するだけですが)、失敗します。

create table #TOP (EDAID int, ParentID char(30), ChildID char(30),
    Position int, OrgQty_modified_manually bit)

これは失敗します:

insert into #TOP
select EDAID, ParentID, ChildID, Position, OrgQty_modified_manually
from EDA_SOBOM
where OrderNr = @OrderNr
    and Position = @Position
    and LN = @LN
    and DL = @DL
    and rtrim(ChildID) = @CurrentPart
    and rtrim(ParentID) = @ParentID

これは機能します:

insert into #TOP
select EDAID, ParentID, ChildID, Position, OrgQty_modified_manually
from EDA_SOBOM

プロシージャ パラメータは次のように宣言されます: @PartID char(30)、@Position int、@OrderNr char(8)、@LN char(2)、@DL char(2)、@ParentID char(30)、@Modified bit出力

私はここで解決策を見つけました: Cannot resolve the collat​​ion conflict between "SQL_Latin1_General_CP1_CI_AS" and "Latin1_General_CI_AS" in the equal to operation .

だから私はCREATEの直後にこれを追加しました:

ALTER TABLE #TOP
  ALTER COLUMN ParentID
    VARCHAR(30) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL

ALTER TABLE #TOP
  ALTER COLUMN ChildID
    VARCHAR(30) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL

そして、それですべてが再び機能しました...しかし、パラメーター比較のみのWHERE句が失敗する理由がわかりません...パラメーターにも照合がありますか?

DB には照合 SQL_Latin1_General_CP1_CI_AS があります。テーブル EDA_SOBOM には、char 列の照合 SQL_Latin1_General_CP1_CI_AS もあります。次のクエリでこれを見つけました。

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

DBレベルやカラムレベルとは別に照合できるところはありますか?

何が起こっているのだろうか...

4

3 に答える 3

1

照合の競合は、異なる照合の文字列を比較する演算子、つまり選択したものの等しい演算子で発生します。

TempDbはサーバーのデフォルトの照合を使用しますが、実際のDbsは異なる照合を使用する場合があるため、DDLを使用して作成された一時テーブルには照合の違いがあります。

等式演算子の後に「collat​​edatabase_default」句を追加して、修正する必要があります。または、次を使用して一時テーブルを作成できます。

select top 0 EDAID, ParentID, ChildID, Position, OrgQty_modified_manually 
into #top
from EDA_SOBOM

これにより、一時テーブルの列がデータベースからデータ型(および照合)を取得するように強制されます。

于 2012-05-11T07:56:19.590 に答える
0

すべてのシステム データベースのデフォルトとして機能するサーバー レベルの照合設定があります。あなたが言ったように、データベースレベルの照合があります。また、列と式には照合を定義できます。

データベースの照合順序がシステム データベース (特に tempdb) と異なる場合、多くの問題が発生します。

私が同意するピーター・ウィシャートの答えを繰り返さずに、製品を開発するときは、許可する照合の柔軟性のレベルを決定する必要があることを追加します。問題を回避するには、その選択に基づいてコードを設計する必要があります。データベース オブジェクトがサーバーの照合順序と一致する必要がない場合は、照合修飾子を適用するか、テーブルが tempdb で作成されるとき、システム テーブルが使用されるとき、または比較が行われるときに使用される照合を制御する必要があります。これは、大規模な製品では大量のコードになる可能性があります。

SQLServer で見過ごされがちな別の照合順序があります。これは、.Net SP または関数で使用されるデフォルトの照合です。その照合順序は、SQLServer プロセスの Windows ユーザー プロファイルに基づいて定義されます。多くの場合、ドキュメントでは照合と呼ばれません。これは、Windows の地域設定の一部です。レジストリでは LCID と呼ばれます。

したがって、データベース、sqlserver、テーブル、列の照合順序がすべて一致する場合でも、CLR ストアド プロシージャ コードで文字列比較を行うと、不一致を回避するコードを記述しない限り、不一致が発生する可能性があります。

于 2012-05-11T08:13:42.310 に答える