web-dev-qa-db-ja.com

SQL Serverはvarchar値を自動比較しますが、比較は同じですが比較は好きではありません

今日、SQL Serverの興味深い動作(2005年と2012年に観察された)に出くわし、誰かが説明してくれることを期待していました。

NVARCHARフィールドで=を使用して比較を行うクエリは、文字列の末尾のスペースを無視しました(または比較前に値を自動トリミングしました)が、like演算子を使用した同じクエリはスペースを無視しませんでした。使用されている照合順序は、2012年のLatin1_General_CI_ASです。

このSQLフィドルを考えてみましょう: http://sqlfiddle.com/#!6/72262/4

like演算子は末尾のスペース文字列の結果を返さないが、=演算子は結果を返すことに注意してください。どうしてこれなの?

ボーナスポイント:VARCHARフィールドでこれを複製することはできません。スペースは両方のデータ型で同じように処理されると思いました-これは本当ですか?

13
WT_W

私の最初の答えは、ANSI_PADDINGフラグがOFFに設定されているため、動作の違いが原因である可能性があることを示唆しています。ただし、これは正しくありません。このフラグはストレージにのみ影響し、等価比較には影響しません。

違いは MicrosoftによるSQL標準の実装 に由来します。標準では、等しいかどうかをチェックする場合、等しい演算子の左側と右側の両方の文字列にを埋め込んで、同じ長さにする必要があると規定されています。これにより、次の結果が説明されます。

insert into test_padding (varchar_clmn, nvarchar_clmn) values ('space ', 'nspace ')
go
-- equality for varchar column
select count(*) from test_padding where varchar_clmn = 'space' -- returns 1
select count(*) from test_padding where varchar_clmn = 'space ' -- returns 1
select count(*) from test_padding where varchar_clmn = 'space    ' --returns 1
-- equality for nvarchar column
select count(*) from test_padding where nvarchar_clmn = 'nspace' -- returns 1
select count(*) from test_padding where nvarchar_clmn = 'nspace ' -- returns 1
select count(*) from test_padding where nvarchar_clmn = 'nspace    ' --returns 1

LIKE演算子は、そのオペランドを埋め込みません。 VARCHARおよびNVARCHAR列タイプでも動作が異なります

-- likeness for varchar column
select count(*) from test_padding where varchar_clmn like 'space' -- returns 1
select count(*) from test_padding where varchar_clmn like 'space ' -- returns 1
select count(*) from test_padding where varchar_clmn like 'space    ' -- returns 0
-- likeness for nvarchar column
select count(*) from test_padding where nvarchar_clmn like 'nspace' -- returns 0
select count(*) from test_padding where nvarchar_clmn like 'nspace ' -- returns 1
select count(*) from test_padding where nvarchar_clmn like 'nspace    ' -- returns 0

ASCIIタイプのLIKE演算子の動作はSQL Server固有であり、Unicodeタイプの場合はANSI準拠です。

15
Ralf

SQLは、ほとんどのデータ処理言語がすべてのフィールド/変数に固定長を使用した時代に生まれました。余分なスペースを含むテキストフィールドの自動パディングもその画像の一部です。その動作に合わせるために、元のSQL CHAR型は、末尾のスペースを無視するために '='演算子に対して明示的に定義されました。 (もし奇妙だと思ったら、テキストに追加された末尾のスペースに実際の実際のビジネスの意味がある説得力のあるケースを見せてください。)

それ以来、SQL CHAR型はあらゆる種類の方向に進化してきましたが、より新しい特定のデータ型が以前のデータ型からいくつかの特性を継承していることは想像に難くありません。

4
Erwin Smout

LIKE(Transact-SQL) のドキュメントで、Microsoftは次のように書いています(強調は私のものです)。

LIKEを使用したパターンマッチング

LIKEはASCIIパターンマッチングとUnicodeパターンマッチングをサポートします。すべての引数...がASCII文字データ型の場合、ASCIIパターンマッチングが実行されます。引数のいずれかがUnicodeデータ型の場合、すべての引数がUnicodeに変換され、Unicodeパターンマッチングが実行されます。LIKEでUnicodeデータ...を使用すると、末尾の空白は重要ですが、非Unicodeデータの場合、末尾の空白は重要ではありません。Unicode LIKEはISO標準と互換性があります。ASCII LIKEは互換性があります以前のバージョンのSQL Server。

1