Domanda

Stamattina mi sono imbattuto in qualcosa di un po' strano e ho pensato di sottoporlo per un commento.

Qualcuno può spiegare perché la seguente query SQL stampa "uguale" quando eseguita su SQL 2008.Il livello di compatibilità DB è impostato su 100.

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

E questo restituisce 0:

select (LEN(' '))

Sembra che il taglio dello spazio venga effettuato automaticamente.Non ho idea se questo fosse il caso nelle versioni precedenti di SQL Server e non ne ho più nessuno per testarlo.

Mi sono imbattuto in questo perché una query di produzione restituiva risultati errati.Non riesco a trovare questo comportamento documentato da nessuna parte.

Qualcuno ha qualche informazione a riguardo?

È stato utile?

Soluzione

varchare l'uguaglianza sono spinosi in TSQL.IL LEN la funzione dice:

Restituisce il numero di caratteri, anziché il numero di byte, dell'espressione stringa data, esclusi gli spazi finali.

Devi usare DATALENGTH per ottenere un vero byte conteggio dei dati in questione.Se disponi di dati Unicode, tieni presente che il valore che ottieni in questa situazione non sarà uguale alla lunghezza del testo.

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

Quando si tratta di uguaglianza delle espressioni, le due stringhe vengono confrontate per l'uguaglianza in questo modo:

  • Ottieni una stringa più corta
  • Blocco con spazi vuoti finché la lunghezza non sarà uguale a quella della corda più lunga
  • Confronta i due

È il passaggio intermedio che causa risultati inaspettati: dopo quel passaggio, stai effettivamente confrontando lo spazio bianco con lo spazio bianco, quindi sono considerati uguali.

LIKE si comporta meglio di = nella situazione degli "spazi vuoti" perché non esegue il riempimento degli spazi vuoti sul modello che stavi cercando di abbinare:

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

Darà eq Mentre:

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

Darà ne

Attento con LIKE Anche se:non è simmetrico:tratta gli spazi bianchi finali come significativi nel modello (RHS) ma non nell'espressione di corrispondenza (LHS).Quanto segue è tratto da Qui:

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

Altri suggerimenti

L'operatore = è T-SQL non è tanto "uguale" come è "sono la stessa parola / frase, secondo le regole di confronto contesto dell'espressione," e LEN è "il numero di caratteri nella parola / frase." Non ci sono regole di confronto di trattare la spazi finali come parte della parola / frase li precede (anche se trattano gli spazi iniziali come parte della stringa che precedono).

Se avete bisogno di distinguere 'questo' da 'questo', non si deve utilizzare il "sono la stessa parola o la frase" operatore perche 'cio' e 'questo' sono la stessa parola.

A contribuire al modo = Works è l'idea che l'operatore di stringa-uguaglianza dovrebbe dipendere i suoi argomenti contenuti e sul contesto di confronto dell'espressione, ma non dovrebbe dipendere dal tipo di argomenti, se sono entrambi i tipi di stringa.

Il concetto del linguaggio naturale di "questi sono la stessa parola" non è in genere abbastanza preciso per poter essere catturata da un operatore matematico come =, e non c'è alcun concetto di tipo stringa in linguaggio naturale. Contesto (vale a dire, le regole di confronto) le questioni (ed esiste in linguaggio naturale) ed è parte della storia, e proprietà aggiuntive (alcuni che sembrano eccentrico) sono parte della definizione di = al fine di renderlo ben definito nel mondo innaturale i dati.

Sulla questione tipo, non vorrebbe cambiare le parole quando sono memorizzati in diversi tipi di stringhe. Ad esempio, il tipo VARCHAR (10), CHAR (10), e CHAR (3) possono tutti contenere rappresentazioni della parola 'gatto', e? = 'Cat' dovrebbe lasciare che a decidere se un valore di uno di questi tipi detiene la parola 'gatto' (con problemi di cassa e l'accento determinati dal collazione).

Risposta al commento di JohnFx:

Utilizzando char e varchar dati nella documentazione in linea. Citando che la mia pagina enfasi:

  

Ogni valore dei dati char e varchar ha un confronto. Regole di confronto definiscono   attributi come i modelli di bit usati per rappresentare ogni carattere,    regole di confronto , e la sensibilità per caso o accentuando.

Sono d'accordo che potrebbe essere più facile da trovare, ma è documentato.

Da segnalare, anche, è che la semantica di SQL, dove = ha a che fare con i dati del mondo reale e il contesto del confronto (in contrapposizione a qualcosa su bit memorizzati sul computer) è stato parte di SQL per un lungo tempo. La premessa di RDBMS e SQL è la rappresentazione fedele dei dati del mondo reale, da cui il supporto per le regole di confronto molti anni prima che idee simili (come CultureInfo) è entrato nel regno dei linguaggi Algol-like. La premessa di queste lingue (almeno fino a poco tempo fa) è stato problem-solving in ingegneria, non la gestione dei dati aziendali. (Recentemente, l'uso delle lingue simili in applicazioni non-engineering come la ricerca sta facendo alcune incursioni, ma Java, C #, e così via sono ancora alle prese con le loro radici non businessy.)

A mio parere, non è giusto criticare SQL per essere diverso da "la maggior parte dei linguaggi di programmazione." SQL è stato progettato per supportare un quadro per la modellazione dei dati di business che è molto diverso dalla progettazione, in modo che il linguaggio è diverso (e migliore per il suo obiettivo).

Heck, quando SQL è stato specificato prima, alcune lingue non avevano alcun tipo di stringa incorporato. E in alcune lingue ancora, l'operatore tra le stringhe non confronta i dati di carattere del tutto uguale, ma confronta i riferimenti! Non sarebbe mi sorprende se in un altro decennio o due, l'idea che == è cultura-dipendente diventa la norma.

Ho trovato questo blog articolo che descrive il comportamento e spiega perché.

  

Lo standard SQL richiede quella stringa   i confronti, in modo efficace, il pad   più breve stringa con caratteri di spazio.   Ciò porta al sorprendente risultato   che N '' = N'' (la stringa vuota   è uguale a una stringa di uno o più spazi   caratteri) e, più in generale qualsiasi   stringa è uguale a un'altra stringa se   differiscono solo per spazi finali. Questo   può essere un problema in alcuni contesti.

Maggiori informazioni sono disponibili anche in MSKB316626

C'era una domanda simile qualche tempo fa in cui ho guardato in un problema simile qui

Invece di LEN ( ' '), l'uso DATALENGTH ('') -. Che ti dà il valore corretto

Le soluzioni sono state di utilizzare una clausola LIKE come spiegato nella mia risposta in là, e / o comprendono una seconda condizione nella clausola WHERE per controllare troppo DATALENGTH.

Avere una lettura di questa domanda e collegamenti in là.

Per confrontare un valore ad uno spazio letterale, è possibile anche utilizzare questa tecnica come alternativa alla dichiarazione LIKE:

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

A volte si ha a che fare con gli spazi nei dati, con o senza altri personaggi, anche se l'idea di utilizzare Null è meglio - ma non sempre utilizzabile. Ho incontrato la situazione descritta e risolto in questo modo:

... dove ( '>' + @space + '<') <> ( '>' + @ space2 + '<')

Naturalmente non farebbe che FPR grande quantità di dati ma funziona veloce e facile per alcune centinaia di linee ...

Herbert

Come distinti record su SELECT con campi car / varchar su SQL Server: Esempio:

declare @mayvar as varchar(10)

set @mayvar = 'data '

select mykey, myfield from mytable where myfield = @mayvar

atteso

MyKey (int) | myfield (varchar10)

1 | 'Dati'

ottenuto

mykey | myfield

1 | 'Dati' 2 | 'Dati'

, anche se scrivo select mykey, myfield from mytable where myfield = 'data' (senza vuoto finale) Ottengo gli stessi risultati.

come ho risolto? In questo modo:

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

e se c'è un indice su myfield, sarà utilizzato in ogni caso.

Spero che sarà utile.

Un altro modo è quello di mettere di nuovo in uno stato che lo spazio ha un valore. ad esempio: sostituire lo spazio con un personaggio noto come il _

if REPLACE('hello',' ','_') = REPLACE('hello ',' ','_')
    print 'equal'
else
    print 'not equal'

ritorna: non uguale

Non è l'ideale, e probabilmente lento, ma è un altro modo veloce in avanti in caso di necessità in fretta.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top