14

Microsoft SQL Server 2008 R2 (最新のサービス パック/パッチを適用) を使用しており、データベースの照合順序は SQL_Latin1_General_CP1_CI_AS です。

次のコード:

SET ANSI_PADDING ON;
GO

CREATE TABLE Test (
   Code VARCHAR(16) NULL
);
CREATE UNIQUE INDEX UniqueIndex
    ON Test(Code);

INSERT INTO Test VALUES ('sample');
INSERT INTO Test VALUES ('sample ');

SELECT '>' + Code + '<' FROM Test WHERE Code = 'sample        ';
GO

次の結果が生成されます。

(1 行が影響を受けます)

メッセージ 2601、レベル 14、状態 1、行 8

一意のインデックス 'UniqueIndex' を持つオブジェクト 'dbo.Test' に重複するキー行を挿入することはできません。重複キーの値は (sample ) です。

ステートメントは終了されました。

‐‐‐‐‐‐‐‐‐‐‐‐</p>

>サンプル<

(1 行が影響を受けます)

私の質問は次のとおりです。

  1. インデックスは末尾のスペースを格納できないと思います。この動作を指定/定義する公式ドキュメントを教えてもらえますか?
  2. この動作を変更する設定はありますか。つまり、'sample' と 'sample' を 2 つの異なる値 (ちなみに) として認識させて、両方をインデックスに含めることができるようにします。
  3. いったいなぜ SELECT が行を返すのでしょうか? インデックスの一意性を削除すると、両方の INSERT が正常に実行され、SELECT が 2 行を返すため、SQL Server は WHERE 句のスペースを使用して非常に面白い/巧妙なことをしているに違いありません。

正しい方向へのヘルプ/ポインタをいただければ幸いです。ありがとう。

4

1 に答える 1

18

末尾の空白の説明:

SQL Server は、文字列をスペースと比較する方法について、ANSI/ISO SQL-92 仕様 (セクション 8.2、一般規則 #3) に従います。ANSI 標準では、比較に使用する文字列を比較する前に文字列の長さが一致するようにパディングが必要です。パディングは、WHERE 句と HAVING 句の述語、およびその他の Transact-SQL 文字列比較のセマンティクスに直接影響します。たとえば、Transact-SQL では、文字列 'abc' と 'abc ' はほとんどの比較操作で同等であると見なされます。

この規則の唯一の例外は、LIKE 述語です。LIKE 述語式の右側に値の末尾にスペースがある場合、SQL Server は比較を行う前に 2 つの値を同じ長さにパディングしません。LIKE 述語の目的は、定義上、単純な文字列の等価性テストではなくパターン検索を容易にすることであるため、これは前述の ANSI SQL-92 仕様のセクションに違反しません。

上記のすべてのケースのよく知られた例を次に示します。

DECLARE @a VARCHAR(10)
DECLARE @b varchar(10)

SET @a = '1'
SET @b = '1 ' --with trailing blank

SELECT 1
WHERE 
    @a = @b 
AND @a NOT LIKE @b
AND @b LIKE @a

末尾の空白とLIKEについての詳細は次のとおりです。

索引について:

末尾のスペースのみによって既存の値と区別される値を指定すると、値が一意でなければならない列への挿入は失敗します。次の文字列はすべて、一意の制約、主キー、または一意のインデックスによって同等と見なされます。同様に、以下のデータを含む既存のテーブルがあり、一意の制限を追加しようとすると、値が同一と見なされるため失敗します。

PaddedColumn
------------
'abc'
'abc '
'abc  '
'abc    '

(ここから撮影。)

于 2012-02-27T06:12:27.277 に答える