Ich bin heute Morgen auf etwas Seltsames gestoßen und dachte, ich würde es zur Kommentierung einreichen.
Kann jemand erklären, warum die folgende SQL-Abfrage "gleich" gedruckt wird, wenn sie mit SQL 2008 ausgeführt wird. Die Datenbankkompatibilitätsstufe ist auf 100 festgelegt.
if '' = ' '
print 'equal'
else
print 'not equal'
Und das gibt 0 zurück:
select (LEN(' '))
Es scheint, als würde der Raum automatisch beschnitten. Ich habe keine Ahnung, ob dies in früheren Versionen von SQL Server der Fall war, und ich habe keine Möglichkeit mehr, es überhaupt zu testen.
Ich bin darauf gestoßen, weil eine Produktionsabfrage falsche Ergebnisse lieferte. Ich kann dieses Verhalten nirgendwo dokumentiert finden.
Hat jemand irgendwelche Informationen dazu?
Antworten:
varchar
s und Gleichheit sind in TSQL heikel. DieLEN
Funktion sagt:Sie müssen verwenden
DATALENGTH
, um eine echtebyte
Anzahl der fraglichen Daten zu erhalten. Wenn Sie Unicode-Daten haben, beachten Sie, dass der Wert, den Sie in dieser Situation erhalten, nicht der Länge des Textes entspricht.Wenn es um die Gleichheit von Ausdrücken geht, werden die beiden Zeichenfolgen auf folgende Gleichheit verglichen:
Dies ist der mittlere Schritt, der zu unerwarteten Ergebnissen führt. Nach diesem Schritt vergleichen Sie Leerzeichen effektiv mit Leerzeichen. Daher werden sie als gleich angesehen.
LIKE
verhält sich besser als=
in der Situation "Leerzeichen", da das Muster, mit dem Sie übereinstimmen wollten, nicht leer aufgefüllt wird:Wird geben
eq
während:Wird geben
ne
Vorsicht
LIKE
: Es ist nicht symmetrisch: Es behandelt nachgestellte Leerzeichen als signifikant im Muster (RHS), nicht jedoch im Übereinstimmungsausdruck (LHS). Folgendes wird von hier genommen :quelle
sql-server-2008 r2
bekomme ich ,@Space Not Like @Space2 @Space2 Not Like @Space
. Irgendeine Idee warum?@Space Not Like @Space2 @Space2 Not Like @Space
Der Operator = ist T-SQL ist nicht so sehr "gleich", sondern "sind dasselbe Wort / dieselbe Phrase gemäß der Zusammenstellung des Kontextes des Ausdrucks", und LEN ist "die Anzahl der Zeichen in dem Wort / der Phrase". Keine Kollatierungen behandeln nachgestellte Leerzeichen als Teil des vorangestellten Wortes / Satzes (obwohl sie führende Leerzeichen als Teil der Zeichenfolge behandeln, der sie vorangehen).
Wenn Sie "dies" von "dies" unterscheiden müssen, sollten Sie den Operator "Sind dasselbe Wort oder dieselbe Phrase" nicht verwenden, da "Dies" und "Dies" dasselbe Wort sind.
Zu way = works trägt die Idee bei, dass der String-Equality-Operator vom Inhalt seiner Argumente und vom Kollatierungskontext des Ausdrucks abhängen sollte, aber nicht von den Argumenttypen, wenn beide Stringtypen sind .
Das natürliche Sprachkonzept von "das sind das gleiche Wort" ist normalerweise nicht präzise genug, um von einem mathematischen Operator wie = erfasst zu werden, und es gibt kein Konzept des Zeichenfolgentyps in natürlicher Sprache. Der Kontext (dh die Kollatierung) ist wichtig (und existiert in natürlicher Sprache) und ist Teil der Geschichte, und zusätzliche Eigenschaften (einige, die skurril erscheinen) sind Teil der Definition von =, um sie in der unnatürlichen Welt von gut definiert zu machen Daten.
Bei der Typproblematik möchten Sie nicht, dass sich Wörter ändern, wenn sie in verschiedenen Zeichenfolgentypen gespeichert werden. Beispielsweise können die Typen VARCHAR (10), CHAR (10) und CHAR (3) alle Darstellungen des Wortes "Katze" enthalten, und? = 'cat' sollte uns entscheiden lassen, ob ein Wert eines dieser Typen das Wort 'cat' enthält (wobei Fall- und Akzentprobleme durch die Sortierung bestimmt werden).
Antwort auf den Kommentar von JohnFx:
Siehe Verwenden von char- und varchar-Daten in Online-Büchern. Zitat von dieser Seite, Hervorhebung von mir:
Ich bin damit einverstanden, dass es einfacher zu finden sein könnte, aber es ist dokumentiert.
Bemerkenswert ist auch, dass die Semantik von SQL, bei der = mit den realen Daten und dem Kontext des Vergleichs zu tun hat (im Gegensatz zu etwas über auf dem Computer gespeicherte Bits), seit langem Teil von SQL ist. Die Prämisse von RDBMS und SQL ist die getreue Darstellung realer Daten, daher die Unterstützung von Kollatierungen viele Jahre bevor ähnliche Ideen (wie CultureInfo) in den Bereich algolähnlicher Sprachen gelangten. Die Prämisse dieser Sprachen war (zumindest bis vor kurzem) die Problemlösung im Ingenieurwesen, nicht die Verwaltung von Geschäftsdaten. (In letzter Zeit hat die Verwendung ähnlicher Sprachen in nicht-technischen Anwendungen wie der Suche einige Fortschritte gemacht, aber Java, C # usw. haben immer noch Probleme mit ihren nicht-geschäftlichen Wurzeln.)
Meiner Meinung nach ist es nicht fair, SQL dafür zu kritisieren, dass es sich von "den meisten Programmiersprachen" unterscheidet. SQL wurde entwickelt, um ein Framework für die Modellierung von Geschäftsdaten zu unterstützen, das sich stark vom Engineering unterscheidet. Daher ist die Sprache anders (und besser für das Ziel).
Als SQL zum ersten Mal angegeben wurde, hatten einige Sprachen keinen integrierten Zeichenfolgentyp. Und in einigen Sprachen vergleicht der Gleichheitsoperator zwischen Zeichenfolgen überhaupt keine Zeichendaten, sondern Referenzen! Es würde mich nicht überraschen, wenn in ein oder zwei weiteren Jahrzehnten die Idee, dass == kulturabhängig ist, zur Norm wird.
quelle
Ich habe diesen Blog-Artikel gefunden, der das Verhalten beschreibt und erklärt, warum.
Weitere Informationen finden Sie auch in MSKB316626
quelle
Vor einiger Zeit gab es eine ähnliche Frage, bei der ich mich hier mit einem ähnlichen Problem befasst habe
LEN(' ')
VerwendenDATALENGTH(' ')
Sie stattdessen - das gibt Ihnen den richtigen Wert.Die Lösungen bestanden darin, eine
LIKE
Klausel zu verwenden , wie in meiner Antwort dort erläutert, und / oder eine zweite Bedingung in dieWHERE
zu überprüfende Klausel aufzunehmenDATALENGTH
ebenfalls .Lesen Sie diese Frage und die Links dort.
quelle
Um einen Wert mit einem Literalraum zu vergleichen, können Sie diese Technik auch als Alternative zur LIKE-Anweisung verwenden:
quelle
So unterscheiden Sie Datensätze bei der Auswahl mit den Feldern char / varchar auf dem SQL Server: Beispiel:
erwartet
mykey (int) | myfield (varchar10)
1 | 'Daten '
erhalten
mykey | mein Feld
1 | 'Daten' 2 | 'Daten '
Selbst wenn ich schreibe
select mykey, myfield from mytable where myfield = 'data'
(ohne endgültiges Leerzeichen), erhalte ich die gleichen Ergebnisse.Wie habe ich gelöst? In diesem Modus:
und wenn es einen Index für myfield gibt, wird dieser jeweils verwendet.
Ich hoffe es wird hilfreich sein.
quelle
Eine andere Möglichkeit besteht darin, es wieder in einen Zustand zu versetzen, in dem der Raum einen Wert hat. Beispiel: Ersetzen Sie das Leerzeichen durch ein Zeichen wie _
Rückgabe: ungleich
Nicht ideal und wahrscheinlich langsam, aber ein weiterer schneller Weg, wenn er schnell benötigt wird.
quelle
Manchmal muss man sich mit Leerzeichen in Daten befassen, mit oder ohne andere Zeichen, obwohl die Idee, Null zu verwenden, besser ist - aber nicht immer verwendbar. Ich bin auf die beschriebene Situation gestoßen und habe sie folgendermaßen gelöst:
Natürlich würden Sie das nicht für große Datenmengen tun, aber es funktioniert schnell und einfach für einige hundert Zeilen ...
quelle