Auto-trim di SQL Server del valore varchar in confronto uguale ma non come confronto


13

Mi sono imbattuto in alcuni comportamenti interessanti su SQL Server (osservati nel 2005 e 2012) oggi che speravo che qualcuno potesse spiegare.

Una query che esegue un confronto utilizzando =su un campo NVARCHAR ha ignorato lo spazio finale nella stringa (o ha automaticamente tagliato il valore prima del confronto) ma la stessa query che utilizza l' likeoperatore non ha ignorato lo spazio. Le regole di confronto utilizzate sono Latin1_General_CI_AS nel 2012.

Considera questo SQL Fiddle: http://sqlfiddle.com/#!6/72262/4

Si noti che l' likeoperatore non restituisce un risultato per la stringa di spazio finale, ma l' =operatore lo fa. Perchè è questo?

Punti bonus: non riesco a replicarlo su un campo VARCHAR, avrei pensato che uno spazio sarebbe stato gestito allo stesso modo in entrambi i tipi di dati - è vero?


Stavo cercando di scrivere un vincolo di controllo per il taglio di una stringa. Ho trovato una soluzione alternativa che è quella di verificare MyString+'x' = ltrim(rtrim(MyString))+'x'come suggerito su questo blog
default.kramer

Risposte:


15

La mia risposta iniziale ha suggerito che il flag ANSI_PADDING impostato su OFF potrebbe essere la causa della differenza di comportamento. Tuttavia, questo non è corretto; questo flag ha effetto solo sulla memoria, ma non sul confronto di uguaglianza.

La differenza deriva dall'implementazione Microsoft dello standard SQL . Lo standard afferma che quando si controlla l'uguaglianza, entrambe le stringhe sinistra e destra dell'operatore di uguaglianza devono essere riempite per avere la stessa lunghezza . Questo spiega i seguenti risultati:

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

L'operatore LIKE non riempie i suoi operandi. Si comporta anche in modo diverso per VARCHARe NVARCHARtipi di colonna :

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

Il comportamento dell'operatore LIKE per il tipo ASCII è specifico di SQL Server; per il tipo Unicode è conforme ANSI.


4

SQL è nato in un'epoca in cui la maggior parte dei linguaggi di elaborazione dati utilizzava lunghezze fisse per ogni campo / variabile. Anche il riempimento automatico dei campi di testo con spazi extra faceva parte di quell'immagine. Per allinearsi a quel comportamento, il tipo SQL CHAR originale è stato definito esplicitamente affinché il suo operatore '=' ignori gli spazi finali. (Se lo trovi strano, mostrami un caso convincente in cui gli spazi finali aggiunti a un testo hanno un reale significato commerciale ).

I tipi di CHAR SQL si sono evoluti in tutti i tipi di direzioni da allora, ma non è inconcepibile che alcuni tipi di dati più moderni abbiano ancora ereditato alcune caratteristiche dai loro predecessori storici.


"mostrami un caso convincente in cui gli spazi finali aggiunti a un testo hanno un reale significato reale per gli affari" - l'archiviazione di dati significativi per gli spazi bianchi, come alcuni output di console grezzi e frammenti XML pre-non sicuri.
Dai

1

Nella documentazione per LIKE (Transact-SQL) , Microsoft scrive (sottolineatura mia):

Pattern Matching usando LIKE

LIKE supporta la corrispondenza del modello ASCII e la corrispondenza del modello Unicode. Quando tutti gli argomenti ... sono tipi di dati di carattere ASCII, viene eseguita la corrispondenza del modello ASCII. Se uno qualsiasi degli argomenti è del tipo di dati Unicode, tutti gli argomenti vengono convertiti in Unicode e viene eseguita la corrispondenza del modello Unicode. Quando usi i dati Unicode ... con LIKE, gli spazi vuoti finali sono significativi; tuttavia, per i dati non Unicode, gli spazi vuoti finali non sono significativi. Unicode LIKE è compatibile con lo standard ISO. ASCII LIKE è compatibile con le versioni precedenti di SQL Server.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.