SQL Server 2008 Leerer String vs. Raum
-
22-09-2019 - |
Frage
Ich lief in etwas ein wenig seltsam an diesem Morgen und dachte, dass ich es für Kommentar einreichen würde.
Kann mir jemand erklären, warum die folgende SQL-Abfrage druckt ‚gleich‘ bei der Ausführung gegen SQL 2008. Der db Kompatibilitätsgrad ist auf 100.
if '' = ' '
print 'equal'
else
print 'not equal'
Und diese liefert 0:
select (LEN(' '))
Es erscheint automatisch Trimmen der Raum zu sein. Ich habe keine Ahnung, ob dies der Fall in früheren Versionen von SQL Server ist, und ich habe nichts mehr herum sogar Test es.
Ich lief dies in, weil eine Produktions Abfrage falsche Ergebnisse zurückkehrt. Ich kann dieses Verhalten nicht irgendwo dokumentiert finden.
Hat jemand irgendwelche Informationen dazu?
Lösung
varchar
s und Gleichheit sind dornige in TSQL. Die LEN
Funktion sagt:
Gibt die Anzahl der Zeichen, anstatt die Anzahl von Bytes, von dem angegebenen String-Ausdruck, ohne nachgestellte Leerzeichen .
Sie müssen DATALENGTH
verwenden, um eine wahre byte
Zählung der Daten in Frage zu kommen. Wenn Sie Unicode-Daten haben, beachten Sie, dass der Wert, den Sie in dieser Situation erhalten nicht die gleiche wie die Länge des Textes sein.
print(DATALENGTH(' ')) --1
print(LEN(' ')) --0
Wenn es um die Gleichheit von Ausdrücken kommt, werden die beiden Strings im Vergleich zur Gleichstellung wie folgt aus:
- Get Shorter Zeichenfolge
- Pad mit Leerzeichen , bis Länge gleich, dass die längeren Zeichenfolge
- Vergleichen Sie die beiden
Es ist die mittlere Stufe, die zu unerwarteten Ergebnissen verursacht - nach diesem Schritt werden Sie effektiv Leerzeichen gegen Leerzeichen Vergleich -. Daher sind sie gleich zu sehen sein
LIKE
benimmt ich besser als =
in der Situation „Rohlinge“, weil es führt kein Auffüllen mit Leerzeichen auf dem Muster, das Sie zu passen versuchen:
if '' = ' '
print 'eq'
else
print 'ne'
geben eq
während:
if '' LIKE ' '
print 'eq'
else
print 'ne'
geben ne
Vorsicht mit LIKE
obwohl: Es ist nicht symmetrisch ist: es behandelt im Muster Leerzeichen als signifikanten Hinter (RHS), aber nicht das Spiel Ausdruck (LHS). Im Folgenden wird genommen von hier :
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
Andere Tipps
Der Operator = ist T-SQL ist nicht so viel „gleich“ wie es ist „sind der gleiche Wort / Satz, nach der Zusammenstellung des Kontexts des Ausdrucks“ und LEN ist „die Anzahl der Zeichen in dem Wort / Phrase." Keine Sortierungen behandeln folgende Leerzeichen als Teil des Wortes / Phrase ihnen vorhergehenden (obwohl sie behandeln führende Leerzeichen als Teil des Strings sie vorangehen).
Wenn Sie zu unterscheiden, ‚this‘ von ‚this‘, sollten Sie nicht den Verwendung „ist das gleiche Wort oder eine Phrase“ Operators, weil ‚dieses‘ und ‚dieses‘ sind das gleiche Wort.
auf dem Weg Beitrag = Arbeiten ist die Idee, dass der String-Gleichheitsoperator auf seine Argumente Inhalte und auf dem Sortierungs Kontext des Ausdrucks abhängen sollte, aber es sollte nicht abhängig von der Art der Argumente, wenn sie beide String-Typen.
Die natürliche Sprache Begriff „diese sind das gleiche Wort“ ist normalerweise nicht präzise genug, um wie = durch einen mathematischen Operator erfasst werden, und es gibt kein Konzept der String-Typ in natürlicher Sprache. Kontext (dh Sortierungs) zählt (und existiert in natürlicher Sprache) und ist ein Teil der Geschichte, und zusätzliche Eigenschaften (einige, die schrulligen scheinen) sind Teil der Definition von =, um es wohldefiniert in der unnatürlichen Welt zu machen Daten.
Auf dem Typ Frage, würden Sie nicht Worte ändern wollen, wenn sie in verschiedenen String-Typen gespeichert sind. Zum Beispiel kann die Typen VARCHAR (10), CHAR (10) und CHAR (3) können alle Halte Darstellungen des Wortes 'Katze', und? = ‚Cat‘ sollte lassen Sie uns, wenn ein Wert von jedem dieser Arten hält das Wort ‚Katze‘ (mit Fragen des Falles und Akzente durch die Sortierungs bestimmt) entscheiden.
Antwort auf JohnFx Kommentar:
Siehe Mit char und varchar Daten in der Onlinedokumentation. Zitiert von dieser Seite, Hervorhebung von mir:
Jeder char und varchar Datenwert hat eine Sortierung. Sortierungen definieren Attribute wie die Bitmuster der einzelnen Zeichen repräsentieren verwendet wird, Vergleichsregeln , und die Empfindlichkeit zu Fall oder Akzentuierung.
stimme ich es einfacher sein könnte zu finden, aber es ist dokumentiert.
Bemerkenswert ist auch, dass SQL Semantik, wo = hat mit den Daten der realen Welt zu tun und dem Kontext des Vergleichs (wie etwa Bits Gegensatz zu etwas auf dem Computer gespeichert) hat für ein langen Teil von SQL gewesen Zeit. Die Prämisse von RDBMS und SQL ist die getreue Darstellung von Daten der realen Welt, damit seine Unterstützung für Sortierungen viele Jahre vor ähnlichen Ideen (wie Culture) trat in das Reich der Algol-ähnliche Sprachen. Die Prämisse dieser Sprachen (zumindest bis vor kurzem) war zur Problemlösung in der Technik, nicht das Management von Geschäftsdaten. (Vor kurzem hat die Verwendung von ähnlichen Sprachen in nicht-technischen Anwendungen wie Suche macht einige Einbrüche, aber Java, C #, und so weiter kämpft noch immer mit ihren nicht-businessy Wurzeln.)
Meiner Meinung nach ist es nicht fair, SQL zu kritisieren, anders zu sein „die meisten Programmiersprachen.“ SQL wurde entwickelt, einen Rahmen für die Geschäftsdatenmodellierung zu unterstützen, die von der Entwicklung sehr unterschiedlich ist, so dass die Sprache ist anders (und besser für das Ziel).
Heck, wenn wurde SQL zuerst angegeben, haben einige Sprachen haben keine integrierte String-Typ. Und noch in einigen Sprachen entspricht der Bediener zwischen Strings keine Zeichendaten überhaupt vergleichen zu können, sondern vergleicht Referenzen! Es würde mich nicht überraschen, wenn in einem anderen Jahrzehnt oder zwei, die Idee, dass == ist kulturabhängig die Norm wird.
Ich fand dieses Blog Artikel , die das Verhalten beschreibt und erklärt, warum.
Der SQL-Standard erfordert, dass die Zeichenfolge Vergleiche, effektiv, Pad die kürzere Zeichenfolge mit Leerzeichen. Dies führt zu dem überraschenden Ergebnis dass N ‚‘ = N‘ '(die leere Zeichenkette gleich eine Reihe von einem oder mehreren Raum Zeichen) und allgemein jede String gleich eine andere Zeichenfolge, wenn sie unterscheiden sich nur durch Leerzeichen. Diese ein Problem in manchen Kontexten sein kann.
Weitere Informationen auch in MSKB316626
Es gab eine ähnliche Frage vor einiger Zeit, wo ich in ein ähnliches Problem sah hier
Statt LEN ( ' '), die Verwendung DATALENGTH ('') -., Dass Sie den richtigen Wert gibt
Die Lösungen wurden eine LIKE-Klausel verwenden, wie in meiner Antwort dort erklärt, und / oder er gibt eine zweite Bedingung in der WHERE-Klausel DATALENGTH zu überprüfen.
Haben Sie einen Lese dieser Frage und Links drin.
Um einen Wert zu einem wörtlichen Raum zu vergleichen, können Sie auch diese Technik als Alternative zu der Aussage LIKE:
IF ASCII('') = 32 PRINT 'equal' ELSE PRINT 'not equal'
Manchmal hat man mit Leerzeichen in Daten beschäftigen, mit oder ohne andere Zeichen, obwohl die Idee der Verwendung von Null ist besser - aber nicht immer brauchbar. Ich habe in der beschriebenen Situation laufen und gelöst es so aus:
... where ( '>' + @space + '<') <> ( '>' + @ space2 + '<')
Natürlich würden Sie, dass fpr große Menge an Daten nicht tun, aber es funktioniert schnell und einfach für einige hundert Zeilen ...
Herbert
Wie verschiedene Datensätze auf ausgewählten Feldern mit char / varchar auf SQL Server: Beispiel:
declare @mayvar as varchar(10)
set @mayvar = 'data '
select mykey, myfield from mytable where myfield = @mayvar
erwartet
mykey (int) | myfield (varchar10)
1 | 'Data'
erhalten
mykey | myfield
1 | 'Data' 2 | 'Data'
auch wenn ich Schreib
select mykey, myfield from mytable where myfield = 'data'
(ohne abschließende blank)
Ich erhalte die gleichen Ergebnisse.
, wie ich gelöst? In diesem Modus:
select mykey, myfield
from mytable
where myfield = @mayvar
and DATALENGTH(isnull(myfield,'')) = DATALENGTH(@mayvar)
und wenn es ein Index auf myfield ist, wird es in jedem Fall verwendet werden.
Ich hoffe, es wird hilfreich sein.
Eine andere Möglichkeit ist es, in einen Zustand zurück zu setzen, dass der Raum Wert hat. zB: Ersetzen Sie den Raum mit einem Charakter wie die bekannten _
if REPLACE('hello',' ','_') = REPLACE('hello ',' ','_')
print 'equal'
else
print 'not equal'
Rückgabe: nicht gleich
Nicht ideal, und wahrscheinlich langsam, aber ist ein weiterer schneller Weg nach vorne, wenn schnell benötigt.