Pertanyaan SQL Server 2008 Empty String vs. Space


Saya mengalami sesuatu yang sedikit aneh pagi ini dan berpikir saya akan mengajukannya untuk komentar.

Dapatkah seseorang menjelaskan mengapa kueri SQL berikut mencetak 'sama' saat dijalankan melawan SQL 2008. Tingkat kompatibilitas db diatur ke 100.

if '' = ' '
    print 'equal'
else
    print 'not equal'

Dan ini mengembalikan 0:

select (LEN(' '))

Tampaknya otomatis memangkas ruang. Saya tidak tahu apakah ini adalah kasus di versi SQL Server sebelumnya, dan saya tidak lagi memiliki sekitar untuk mengujinya.

Saya mengalami ini karena permintaan produksi mengembalikan hasil yang salah. Saya tidak dapat menemukan perilaku ini didokumentasikan di mana saja.

Adakah yang punya informasi tentang ini?


75
2017-09-09 13:56


asal


Jawaban:


varchars dan kesetaraan berduri di TSQL. Itu LEN fungsi mengatakan:

Mengembalikan jumlah karakter, bukan jumlah byte, dari ekspresi string yang diberikan, tidak termasuk membuntuti kosong.

Anda perlu menggunakan DATALENGTH untuk mendapatkan yang benar byte hitungan data yang dipertanyakan. Jika Anda memiliki data unicode, perhatikan bahwa nilai yang Anda dapatkan dalam situasi ini tidak akan sama dengan panjang teks.

print(DATALENGTH(' ')) --1
print(LEN(' '))        --0

Ketika menyangkut persamaan ekspresi, kedua string tersebut dibandingkan untuk persamaan seperti ini:

  • Dapatkan string yang lebih pendek
  • Pad dengan kosong sampai panjang sama dengan string yang lebih panjang
  • Bandingkan keduanya

Ini adalah langkah tengah yang menyebabkan hasil yang tidak diharapkan - setelah langkah itu, Anda secara efektif membandingkan spasi putih terhadap spasi putih - sehingga mereka terlihat sama.

LIKE berperilaku lebih baik daripada = dalam situasi "kosong" karena tidak melakukan pelapisan kosong pada pola yang Anda coba padankan:

if '' = ' '
print 'eq'
else
print 'ne'

Akan memberi eq sementara:

if '' LIKE ' '
print 'eq'
else
print 'ne'

Akan memberi ne

Hati-hati dengan LIKE meskipun: itu tidak simetris: ia memperlakukan trailing whitespace sebagai signifikan dalam pola (RHS) tetapi bukan ekspresi pertandingan (LHS). Berikut ini diambil dari sini:

declare @Space nvarchar(10)
declare @Space2 nvarchar(10)

set @Space = ''
set @Space2 = ' '

if @Space like @Space2
print '@Space Like @Space2'
else
print '@Space Not Like @Space2'

if @Space2 like @Space
print '@Space2 Like @Space'
else
print '@Space2 Not Like @Space'

@Space Not Like @Space2
@Space2 Like @Space

78
2017-09-09 14:14



Operator = adalah T-SQL tidak begitu banyak "sama dengan" sebagaimana adanya "adalah kata / frasa yang sama, sesuai dengan susunan konteks ekspresi," dan LEN adalah "jumlah karakter dalam kata / frasa." Tidak ada kolase yang mengatasi kekosongan sebagai bagian dari kata / frasa yang mendahului mereka (meskipun mereka memperlakukan kosong sebagai bagian dari string yang mendahului).

Jika Anda perlu membedakan 'ini' dari 'ini', Anda tidak boleh menggunakan operator "kata atau frasa yang sama" karena 'ini' dan 'ini' adalah kata yang sama.

Kontribusi terhadap cara = berfungsi adalah gagasan bahwa operator string-kesetaraan harus bergantung pada isi argumennya dan pada konteks pengumpulan dari ekspresi, tetapi seharusnya tidak bergantung pada jenis argumen, jika keduanya merupakan tipe string .

Konsep bahasa alami dari "ini adalah kata yang sama" tidak biasanya cukup tepat untuk dapat ditangkap oleh operator matematika seperti =, dan tidak ada konsep tipe string dalam bahasa alami. Konteks (yaitu, pengumpulan) penting (dan ada dalam bahasa alami) dan merupakan bagian dari cerita, dan properti tambahan (beberapa yang tampak aneh) adalah bagian dari definisi = untuk membuatnya didefinisikan dengan baik di dunia yang tidak alami data.

Pada jenis masalah, Anda tidak ingin kata-kata berubah ketika disimpan dalam jenis string yang berbeda. Misalnya, jenis VARCHAR (10), CHAR (10), dan CHAR (3) dapat menyimpan representasi kata 'kucing', dan? = 'kucing' harus membiarkan kita memutuskan apakah nilai dari salah satu dari jenis ini mengandung kata 'kucing' (dengan masalah kasus dan aksen yang ditentukan oleh pemeriksaan).

Tanggapan untuk komentar JohnFx:

Lihat Menggunakan Data char dan varchar di Buku Online. Mengutip dari halaman itu, penekanan saya:

Setiap nilai data char dan varchar memiliki pemeriksaan. Rangkaian menentukan   atribut seperti pola bit yang digunakan untuk mewakili setiap karakter,    aturan perbandingan, dan kepekaan terhadap kasus atau aksen.

Saya setuju itu lebih mudah ditemukan, tetapi didokumentasikan.

Perlu dicatat juga, adalah bahwa semantik SQL, di mana = ada hubungannya dengan data dunia nyata dan konteks perbandingan (dibandingkan dengan sesuatu tentang bit yang tersimpan di komputer) telah menjadi bagian dari SQL untuk waktu yang lama. Premis RDBMS dan SQL adalah representasi yang setia dari data dunia nyata, maka dukungannya untuk pengumpulan bertahun-tahun sebelum ide-ide serupa (seperti CultureInfo) masuk ke ranah bahasa yang mirip dengan Algol. Premis bahasa-bahasa tersebut (paling tidak hingga baru-baru ini) adalah pemecahan masalah dalam rekayasa, bukan pengelolaan data bisnis. (Baru-baru ini, penggunaan bahasa yang serupa dalam aplikasi non-teknis seperti pencarian membuat beberapa terobosan, tetapi Java, C #, dan sebagainya masih berjuang dengan akar non-bisnisnya.)

Menurut pendapat saya, tidak adil untuk mengkritik SQL karena berbeda dari "sebagian besar bahasa pemrograman." SQL dirancang untuk mendukung kerangka kerja untuk pemodelan data bisnis yang sangat berbeda dari teknik, sehingga bahasanya berbeda (dan lebih baik untuk tujuannya).

Heck, ketika SQL pertama kali ditentukan, beberapa bahasa tidak memiliki tipe string bawaan. Dan dalam beberapa bahasa, operator yang sama antara string tidak membandingkan data karakter sama sekali, tetapi membandingkan referensi! Itu tidak akan mengejutkan saya jika dalam satu atau dua dekade lagi, gagasan bahwa == bergantung pada budaya menjadi norma.


17
2017-09-09 15:20



aku menemukan ini artikel blog yang menggambarkan perilaku dan menjelaskan alasannya.

Standar SQL membutuhkan string itu   perbandingan, efektif, pad   string lebih pendek dengan karakter spasi.   Ini mengarah pada hasil yang mengejutkan   bahwa N '' = N '' (string kosong   sama dengan string satu atau lebih banyak ruang   karakter) dan lebih umum lagi   string sama dengan string lain jika mereka   hanya berbeda dengan spasi tambahan. Ini   bisa menjadi masalah dalam beberapa konteks.

Informasi lebih lanjut juga tersedia di MSKB316626


9
2017-09-09 15:03



Ada pertanyaan serupa beberapa saat yang lalu ketika saya melihat masalah yang sama sini

Alih-alih LEN (''), gunakan DATALENGTH ('') - yang memberi Anda nilai yang benar.

Solusinya adalah menggunakan SEPERTI klausul seperti yang dijelaskan dalam jawaban saya di sana, dan / atau termasuk kondisi kedua di klausa WHERE untuk memeriksa DATALENGTH juga.

Bacalah pertanyaan dan tautan di sana.


4
2017-09-09 14:12



Untuk membandingkan nilai ke ruang literal, Anda juga dapat menggunakan teknik ini sebagai alternatif untuk pernyataan LIKE:

IF ASCII('') = 32 PRINT 'equal' ELSE PRINT 'not equal'

3
2018-02-24 20:03



Kadang-kadang kita harus berurusan dengan spasi dalam data, dengan atau tanpa karakter lain, meskipun ide menggunakan Null lebih baik - tetapi tidak selalu dapat digunakan. Saya mengalami situasi yang dijelaskan dan memecahkannya dengan cara ini:

... di mana ('>' + @space + '<') <> ('>' + @ space2 + '<')

Tentu saja Anda tidak akan melakukan itu fpr sejumlah besar data tetapi bekerja cepat dan mudah untuk beberapa ratus baris ...

Herbert


0
2018-01-16 14:37



Cara membedakan catatan pada pilih dengan field char / varchar pada server sql: contoh:

declare @mayvar as varchar(10)

set @mayvar = 'data '

select mykey, myfield from mytable where myfield = @mayvar

diharapkan

mykey (int) | myfield (varchar10)

1 | 'data'

diperoleh

mykey | myfield

1 | 'data' 2 | 'data'

bahkan jika saya menulis select mykey, myfield from mytable where myfield = 'data' (tanpa akhir kosong) Saya mendapatkan hasil yang sama.

bagaimana saya memecahkannya? Dalam mode ini:

select mykey, myfield
from mytable
where myfield = @mayvar 
and DATALENGTH(isnull(myfield,'')) = DATALENGTH(@mayvar)

dan jika ada indeks di myfield, itu akan digunakan dalam setiap kasus.

Saya berharap ini akan membantu.


0
2018-04-14 15:45