SQL Server auto-trim nilai varchar dalam perbandingan yang sama tetapi tidak seperti perbandingan

13

Saya menemukan beberapa perilaku yang menarik pada SQL Server (diamati pada 2005 dan 2012) hari ini bahwa saya berharap seseorang dapat menjelaskan.

Kueri yang melakukan perbandingan menggunakan =pada bidang NVARCHAR mengabaikan ruang tambahan dalam string (atau otomatis memotong nilai sebelum perbandingan) tetapi kueri yang sama menggunakan likeoperator tidak mengabaikan ruang. Kolasi yang digunakan adalah Latin1_General_CI_AS pada 2012.

Pertimbangkan SQL Fiddle ini: http://sqlfiddle.com/#!6/72262/4

Perhatikan bahwa likeoperator tidak mengembalikan hasil untuk string spasi tambahan, tetapi =operator melakukannya. Kenapa ini?

Poin bonus: Saya tidak dapat meniru ini pada bidang VARCHAR, saya akan berpikir bahwa ruang akan ditangani dengan cara yang sama di kedua tipe data - apakah ini benar?

WT_W
sumber
Saya mencari untuk menulis batasan cek bahwa string dipangkas. Saya menemukan solusi yang untuk memeriksa bahwa MyString+'x' = ltrim(rtrim(MyString))+'x'seperti yang disarankan di blog ini
default.kramer

Jawaban:

15

Jawaban awal saya menyarankan bahwa bendera ANSI_PADDING yang disetel ke MATI mungkin merupakan penyebab perbedaan perilaku. Namun, ini tidak benar; bendera ini hanya memiliki efek pada penyimpanan, tetapi bukan perbandingan kesetaraan.

Perbedaannya berasal dari penerapan standar SQL oleh Microsoft . Standar menyatakan bahwa ketika memeriksa kesetaraan, kedua string kiri dan kanan operator kesetaraan harus diisi agar memiliki panjang yang sama . Ini menjelaskan hasil-hasil berikut:

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

Operator LIKE tidak memasang operan. Itu juga berperilaku berbeda untuk VARCHARdan NVARCHARjenis kolom :

-- 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

Perilaku operator LIKE untuk tipe ASCII adalah khusus SQL Server; untuk jenis Unicode itu adalah ANSI-compliant.

Ralf
sumber
4

SQL lahir di era ketika sebagian besar bahasa pemrosesan data menggunakan panjang tetap untuk setiap bidang / variabel. Padding otomatis bidang teks dengan spasi tambahan juga merupakan bagian dari gambar itu. Untuk sejajar dengan perilaku itu, tipe SQL CHAR asli secara eksplisit didefinisikan untuk operator '=' untuk mengabaikan spasi tambahan. (Jika Anda merasa aneh, tunjukkan pada saya kasus yang menarik di mana spasi tambahan yang ditambahkan ke teks memiliki arti bisnis nyata yang sebenarnya .)

SQL CHAR tipe telah berevolusi dalam segala macam arah sejak itu, tetapi tidak terbayangkan bahwa tipe data yang lebih modern tertentu masih mewarisi beberapa karakteristik dari pendahulunya.

Erwin Smout
sumber
"tunjukkan pada saya kasus yang menarik di mana spasi tambahan yang ditambahkan ke teks memiliki arti bisnis nyata yang sebenarnya" - menyimpan data signifikan spasi-putih, seperti output konsol mentah tertentu dan fragmen XML yang tidak aman.
Dai
1

Dalam dokumentasi untuk LIKE (Transact-SQL) , Microsoft menulis (penekanan saya):

Pencocokan Pola dengan Menggunakan LIKE

LIKE mendukung pencocokan pola ASCII dan pencocokan pola Unicode. Ketika semua argumen ... adalah tipe data karakter ASCII, pencocokan pola ASCII dilakukan. Jika salah satu argumen dari tipe data Unicode, semua argumen dikonversi ke Unicode dan pencocokan pola Unicode dilakukan. Saat Anda menggunakan data Unicode ... dengan LIKE, trailing blank adalah signifikan; Namun, untuk data non-Unicode, trailing blank tidak signifikan. Unicode LIKE kompatibel dengan standar ISO. ASCII LIKE kompatibel dengan versi SQL Server sebelumnya.

Michel de Ruiter
sumber