N'Șc 'は、Latin1_General_CI_AS照合を使用してN'C'の重複キーを検討しました


11

NVARCHAR(50)列を含む一意のキーを持つテーブルがあります(正しいかどうかはわかりますが、あります)。そのため、挿入しようとすると、ȘcまたはC(挿入の順序は関係ありません)、照合の問題により2番目の挿入で中断します。ここにエラーがあります:

(1行が影響を受けました)メッセージ2601、レベル14、状態1、行16一意のインデックス 'IX_TestT'を持つオブジェクト 'dbo.testT'に重複するキー行を挿入できません。重複するキーの値は(C)です。

返品を選択:

ここに画像の説明を入力してください

データベースのデフォルトの照合はLatin1_General_CI_ASです。既存の構造をあまり変更せずに、その解決方法をしばらく探しましたが、機能する方法を見つけることができませんでした。さまざまな照合順序と組み合わせを試しましたが、すべて失敗します。まだ展開されていないキャラクターの展開などについて(ここここ)を読んでください。これは、問題を再現するために使用しているサンプルコードです。自由に変更し、これを解決するのに役立つと思われるものをお勧めします。

CREATE TABLE testT (
    [Default_Collation]     [NVARCHAR] (50) COLLATE DATABASE_DEFAULT,
    [Latin1_General_CI_AS]  [NVARCHAR] (50) COLLATE Latin1_General_CI_AS,
    [Latin1_General_CI_AI]  [NVARCHAR] (50) COLLATE Latin1_General_CI_AI,
    [SQL_Collation]         [NVARCHAR] (50) COLLATE SQL_Latin1_General_CP1_CI_AS);
CREATE UNIQUE CLUSTERED INDEX [IX_TestT] ON [dbo].[testT] ([Default_Collation])
ON [PRIMARY]
GO

INSERT INTO testT
SELECT  N'Șc',  --COLLATE Latin1_General_CI_AS
        N'Șc',  --COLLATE Latin1_General_CI_AS
        N'Șc',  --COLLATE Latin1_General_CI_AS
        N'Șc'   --COLLATE Latin1_General_CI_AS

INSERT INTO testT
SELECT  N'C'    --COLLATE Latin1_General_CI_AS 
        ,N'C'   --COLLATE Latin1_General_CI_AS
        ,N'C'   --COLLATE Latin1_General_CI_AS
        ,N'C'   --COLLATE SQL_Latin1_General_CP1_CI_AS

SELECT * FROM testT;

DROP TABLE testT;

回答:


10

問題は、古いSQL Server照合順序(つまり、名前がで始まるものSQL_)とWindows照合順序の最初の2つのバージョン(80SQL Server 2000に付属していて、名前にバージョン番号がない90シリーズ、およびSQL Server 2005に付属)には、非常に多くの文字の並べ替えの重みがありません。これは100、SQL Server 2008に付属するシリーズの照合順序以降、ほとんどが修正されました。

以下の例でわかるように、Șバイナリ以外のバージョン80または90照合(およびSQL Server照合)を使用すると、文字は空の文字列と一致します。これは、どちらも同じソートウェイト0です。何もありません。なだ。これは、(シリーズ100の照合順序を使用して)と比較する場合、実際には(テスト#1)と比較N'Șc'していることを意味しN'C'ます。N'c'N'C'

SELECT 1 WHERE N'Șc' = N'C' COLLATE Latin1_General_CS_AS;
-- no result (due to "c" and "C" being different case)

SELECT 2 WHERE N'Ș' = N'' COLLATE SQL_Latin1_General_CP1_CI_AS;
SELECT 3 WHERE N'Ș' = N'' COLLATE Latin1_General_CI_AS;

SELECT 4 WHERE N'Ș' = N'' COLLATE Latin1_General_BIN2;
-- no result (due to "Ș" still being a code point and empty string has no code points)

SELECT 5 WHERE N'Ș' = N'' COLLATE Latin1_General_100_CI_AS;
-- no result (due to "Ș" finally having a sort weight in 100 series Collations)

SELECT 6 WHERE N'Ș' = N'' COLLATE Chinese_PRC_CI_AI;
SELECT 7 WHERE N'Ș' = N'' COLLATE Chinese_PRC_90_CI_AI;

SELECT 8 WHERE N'Ș' = N'' COLLATE Indic_General_90_CI_AI;
SELECT 9 WHERE N'Ș' = N'' COLLATE Indic_General_100_CI_AI;
-- no result (due to "Ș" finally having a sort weight in 100 series Collations)

そのため、残念ながら、PKを削除し、列を変更して100レベルの照合順序(例:)にLatin1_General_100_CI_AS_SCしてから、PKを再作成する必要があります。現在の照合との提案された照合の違いは、末尾の100 の両方_SCであるため、補助文字を適切に処理できることに注意してください。

これは、次のことを行う必要があるという意味ではありませ

  1. 他のテーブルの照合順序を変更する(それらがNVARCHARPKでと同じ設定になっている場合を除く)
  2. データベースのデフォルトの照合順序を変更します。DBの照合順序を変更しないとの主な問題はやっ間の行動の違いがあるだろうということですtable.column = N'Ș'@variable = N'Ș'、変数と文字列リテラルは、データベースの既定の照合順序を使用しているため。

この動作の例については、次のブログ投稿の「補足文字」セクションをご覧ください。

Uni-Code:T-SQL識別子の有効な文字の真のリストの検索、パート2/2(区切り識別子)

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