50 votes

Clause WHERE SQL correspondant aux valeurs avec des espaces de fin

Dans SQL Server 2008, j'ai une table nommée Zone avec une colonne ZoneReference varchar(50) not null en tant que clé primaire.

Si j'exécute la requête suivante:

select '"' + ZoneReference + '"' as QuotedZoneReference
from Zone
where ZoneReference = 'WF11XU'

J'obtiens le résultat suivant:

"WF11XU "

Remarque l'espace de fin.

Comment est-ce possible? Si l'espace de fin est vraiment, là, sur cette ligne, alors je m'attends à le retour à zéro des résultats, donc je suis en supposant que c'est quelque chose d'autre que SQL Server Management Studio affiche bizarrement.

Dans le code C# appelant zoneReference.Trim() le supprime, ce qui suggère qu'il est une sorte de caractère d'espacement.

Quelqu'un peut-il aider?

75voto

Mark Byers Points 318575

C'est le résultat attendu: dans SQL Server l' = de l'opérateur ignore les espaces de fin lors de la prise de la comparaison.

SQL Server suit la norme ANSI/ISO SQL-92 cahier des charges (Section 8.2 , les règles Générales n ° 3) sur la manière de comparer des chaînes de caractères avec des espaces. La norme requiert de remplissage pour les chaînes de caractères utilisées dans les comparaisons de sorte que leurs longueurs de match avant de les comparer. Le rembourrage affecte directement la sémantique de l'endroit et AVOIR clause de prédicats et d'autres instructions Transact-SQL comparaisons de chaînes. Par exemple, les instructions Transact-SQL considère les chaînes de caractères " abc " et " abc " pour avoir l'équivalent pour la plupart des opérations de comparaison.

La seule exception à cette règle est le prédicat LIKE. Lorsque le côté droit d'un prédicat LIKE expression dispose d'une valeur avec un espace arrière, SQL Server n'est pas pavé que les deux valeurs de la même longueur avant la comparaison. Parce que le but de la COMME prédicat, par définition, est de faciliter le modèle de recherche plutôt que comme une simple chaîne de tests d'égalité, cela ne viole pas l'article de la norme ANSI SQL-92 spécifications mentionnées plus tôt.

Source

7voto

Paul Chernoch Points 1589

Les espaces ne sont pas toujours ignoré. J'ai connu ce problème aujourd'hui. Ma table avait colonnes NCHAR et a été rejoint de données VARCHAR. Parce que les données dans la table n'était pas aussi large que dans son domaine, des espaces ont été ajoutés automatiquement par SQL Server.

J'ai eu un ITVF (fonction table en ligne) qui a eu varchar paramètres. Les paramètres ont été utilisés dans une JOINTURE de la table avec la NCHAR champs.

Les jointures ont échoué parce que les données transmises à la fonction n'ont pas d'espaces, mais les données dans la table de fait. Pourquoi était-ce?

J'ai été faire trébucher sur la PRIORITÉ des types de DONNÉES. (Voir http://technet.microsoft.com/en-us/library/ms190309.aspx)

Lors de la comparaison des chaînes de différents types, la priorité inférieure est converti à la priorité plus élevée de type avant la comparaison. Donc, mon VARCHAR paramètres ont été convertis en NCHARs. Le NCHARs ont été comparés, et apparemment, les espaces ont été importants.

Comment ai-je résoudre ce problème? J'ai changé la définition de la fonction à utiliser NVARCHAR paramètres, qui sont d'une priorité plus élevée que NCHAR. Maintenant, le NCHARs ont été modifiés automatiquement par SQL Server dans NVARCHARs et les espaces ont été ignorés.

Pourquoi n'ai-je pas simplement effectuer une RTRIM? Les tests ont révélé que RTRIM tué la performance, de la prévention de la JOINTURE des optimisations SQL Server, autrement, aurait utilisé.

Pourquoi ne pas changer le type de données de la table? Les tables sont déjà installés sur les sites des clients, et ils ne veulent pas exécuter les scripts de maintenance (temps + argent pour payer les Administrateurs de bases de données) ou de nous donner accès à leurs machinines (compréhensible).

3voto

James Wiseman Points 18347

Oui, Mark a raison. Exécutez le SQL suivant:

 create table #temp (name varchar(15))
insert into #temp values ('james ')
select '"' + name + '"' from #temp where name ='james'
select '"' + name + '"' from #temp where name like 'james'
drop table #temp
 

Mais l'affirmation à propos de la déclaration 'like' semble ne pas fonctionner dans l'exemple ci-dessus. Sortie:

 (1 row(s) affected)

-----------------
"james "

(1 row(s) affected)


-----------------
"james "

(1 row(s) affected)
 

EDIT: Pour le faire fonctionner, vous pouvez mettre à la fin:

 and name <> rtrim(ltrim(name))
 

Moche quand même.

EDIT2: Compte tenu des commentaires ci-dessus, ce qui suit fonctionnerait:

 select '"' + name + '"' from #temp where 'james' like name
 

-3voto

byte_slave Points 739

essayer

     select Replace('"' + ZoneReference + '"'," ", "") as QuotedZoneReference from Zone where ZoneReference = 'WF11XU'
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X