77 votes

Chaîne vide SQL Server 2008 et espace

Je suis tombé sur quelque chose d'un peu bizarre ce matin et j'ai pensé qu'il soumet pour commentaire.

Quelqu'un peut m'expliquer pourquoi la requête SQL suivante prints "égaux", lorsqu'il est exécuté sur SQL 2008. La db le niveau de compatibilité est fixé à 100.

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

Et cela renvoie 0:

select (LEN(' '))

Il semble être auto élagage de l'espace. Je n'ai aucune idée si c'était le cas dans les versions précédentes de SQL Server, et je n'ai plus tout autour de même de la tester.

J'ai couru dans la ce parce que la production de la requête a été de retourner des résultats incorrects. Je ne trouve pas ce comportement documenté n'importe où.

Personne ne dispose d'aucune information à ce sujet?

79voto

butterchicken Points 4768

varchars et l'égalité sont épineux en TSQL. L' LEN fonction dit:

Renvoie le nombre de caractères, plutôt que le nombre d'octets, de l'expression de chaîne donnée, à l'exclusion des espaces à droite.

Vous devez utiliser DATALENGTH d'obtenir un vrai byte nombre de données en question. Si vous avez des données unicode, notez que la valeur que vous obtenez dans cette situation ne sera pas la même que la longueur du texte.

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

Quand il s'agit de l'égalité des expressions, les deux chaînes sont comparées pour l'égalité comme ceci:

  • Réduction de la taille de la chaîne
  • Pad avec des blancs jusqu'à ce que la longueur est égale à celle de l'allongement de la chaîne
  • Comparer les deux

C'est l'étape intermédiaire qui est à l'origine des résultats inattendus - après cette étape, vous êtes effectivement en comparant les espaces à l'encontre de blanc, par conséquent, ils sont considérés comme égaux.

LIKE se comporte mieux que = dans les "blancs" de la situation, car il n'effectue pas de vide-rembourrage sur le modèle que vous étiez en train de match:

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

Donnera eq tout en:

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

Donnera ne

Attention avec l' LIKE bien: il n'est pas symétrique: il traite de fuite d'espaces comme significatif dans le modèle (RHS), mais pas le match de l'expression (LHS). Ce qui suit est tiré à partir d' ici:

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

17voto

Steve Kass Points 4738

L'opérateur = est T-SQL n'est pas tellement "équivaut à" comme il est "sont le même mot/la phrase, selon le classement de l'expression du contexte," et LEN est "le nombre de caractères dans le mot/la phrase." Pas de classements traiter les espaces à droite comme faisant partie du mot ou de la phrase qui précède (bien qu'ils ne traiter les espaces à gauche comme faisant partie de la chaîne qu'ils précèdent).

Si vous avez besoin de distinguer " ce " de "ce", vous ne devriez pas utiliser le "sont le même mot ou la phrase" opérateur parce que "ceci" et "cela" sont le même mot.

En contribuant à la façon = œuvres, c'est l'idée que la chaîne-opérateur d'égalité doit dépendre de ses arguments contenu et sur le classement contexte de l'expression, mais il ne faut pas compter sur les types d'arguments, s'ils sont les deux types de chaînes.

Le langage naturel concept de "ces mots sont les mêmes" n'est généralement pas assez précis pour être en mesure d'être capturé par un opérateur mathématique comme =, et il n'y a pas de notion de type chaîne de caractères en langage naturel. Contexte (c'est à dire, classement) questions (et existe dans le langage naturel) et fait partie de l'histoire, et les propriétés supplémentaires (certains qui semblent bizarres) font partie de la définition de l' = afin de le rendre bien définis dans le monde artificiel de données.

Sur le type de question, vous ne voulez pas de mots pour changer lorsqu'ils sont stockés dans différents types de chaînes. Par exemple, les types VARCHAR(10) CHAR(10), et CHAR(3) peuvent tous tenir représentations du mot 'chat', et ? = 'cat' devrait nous laisser décider si une valeur de l'un de ces types détient le mot "chat" (avec les questions de cas et de l'accent déterminé par le classement.

Réponse à JohnFx commentaire:

Voir l'Aide de Données char et varchar dans la documentation en Ligne. Citant cette page, c'est moi qui souligne:

Chaque char et varchar valeur de données dispose d'un classement. Les classements définir des attributs tels que les modèles de bits utilisés pour représenter chaque caractère, les règles de comparaison, et la sensibilité à la casse ou à l'accentuation.

Je suis d'accord, il pourrait être plus facile à trouver, mais il est documenté.

Intéressant de noter, aussi, c'est que SQL est de la sémantique, où = a à voir avec le monde réel des données et le contexte de la comparaison (par opposition à quelque chose à propos de bits stockés sur l'ordinateur) a été une partie de SQL pour une longue période de temps. La prémisse de Sgbdr et SQL est la représentation fidèle des données du monde réel, d'où son soutien pour les classements de nombreuses années avant que des idées similaires (tels que CultureInfo) est entré dans le champ de l'Algol-comme les langues. Le principe de ces langues (au moins jusqu'à très récemment) était de résolution de problèmes en génie, pas de gestion de données de l'entreprise. (Récemment, l'utilisation de langues non-ingénierie des applications telles que la recherche fait des percées, mais Java, C#, et ainsi de suite sont encore aux prises avec leur non-businessy racines.)

À mon avis, ce n'est pas juste de critiquer SQL pour être différente de la plupart des langages de programmation." SQL a été conçu pour soutenir un cadre pour les entreprises de la modélisation de données, ce qui est très différent de l'ingénierie, de sorte que la langue est différente (et mieux pour son but).

Heck, lorsque SQL abord été spécifiée, certaines langues n'ont pas tous intégré type de chaîne. Et dans certaines langues encore, l'opérateur = entre des chaînes de caractères n'est pas de comparer les données de caractère à tous, mais compare les références! Il ne m'étonne pas si dans une décennie ou deux, l'idée que l' == est de la culture-dépendante devient la norme.

9voto

JohnFx Points 23761

J'ai trouvé cet article de blog qui décrit le comportement et explique pourquoi.

La norme SQL exige que la chaîne les comparaisons, effectivement, le pad courte chaîne de caractères d'espace. Ce qui conduit au résultat surprenant qui N" = N "" (la chaîne vide est égal à une chaîne d'un ou de plus d'espace caractères) et plus généralement de tout la chaîne est égale à une autre chaîne si ils ne diffèrent que par des espaces. Cette peut être un problème dans certains contextes.

Plus d'informations également disponibles dans MSKB316626

4voto

AdaTheDev Points 53358

Il y a une question similaire il y a un moment où j'ai regardé dans un problème similaire ici

Au lieu de LEN(' '), utilisez DATALENGTH(' ') - qui vous donne la bonne valeur.

Les solutions étaient à l'utilisation d'une clause LIKE comme expliqué dans ma réponse il y a, et/ou d'ajouter un 2ème condition de la clause where pour vérifier DATALENGTH trop.

Avoir une lecture de la question et des liens.

3voto

David G Points 21

Pour comparer une valeur à un espace littéral, vous pouvez également utiliser cette technique comme alternative à l'instruction LIKE:

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

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: