2012-04-27 8 views
5

I Tabelle in MySQL so erstellt:String vergleichen genau in Abfrage MySQL

DROP TABLE IF EXISTS `barcode`; 
CREATE TABLE `barcode` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `code` varchar(40) COLLATE utf8_bin DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 


INSERT INTO `barcode` VALUES ('1', 'abc'); 

INSERT INTO `barcode` VALUES ('2', 'abc '); 

Dann habe ich Daten aus der Tabelle Barcode-Abfrage:

SELECT * FROM barcode WHERE `code` = 'abc '; 

Das Ergebnis ist:

+-----+-------+ 
| id | code | 
+-----+-------+ 
| 1 | abc | 
+-----+-------+ 
| 2 | abc | 
+-----+-------+ 

Aber ich möchte das Ergebnis nur 1 Datensatz einstellen. Ich erarbeite Abhilfe mit:

SELECT * FROM barcode WHERE `code` = binary 'abc '; 

Das Ergebnis ist 1 Datensatz. Aber ich benutze NHibernate mit MySQL zum Generieren von Abfragen aus Mappingtabellen. So, wie diesen Fall zu lösen?

+0

Das nächste Mal, schauen Sie sich an, wie Ihre Frage kommt (es gibt eine Vorschau-Box unter Ihrem Textfeld), und wenn es ein Chaos aussieht, beheben Sie es :). Verwenden Sie eine großzügige Menge der "{}' Taste oben für Code ..... – Nanne

+1

Könnten Sie NHibenate Mappings und Methoden, die Sie verwenden, um Abfrage generieren? Warum verwenden Sie Native-SQL mit NHibernate? Ich denke, Sie sollten Criteria API oder HQL verwenden. –

+1

aus der Dokumentation: ["Alle MySQL-Kollatierungen sind vom Typ PADSPACE. Dies bedeutet, dass alle CHAR- und VARCHAR-Werte in MySQL ohne Berücksichtigung nachfolgender Leerzeichen verglichen werden"] (http://dev.mysql.com/doc/refman/ 5.0/de/char.html) – Kaii

Antwort

0

Ich gehe davon aus Sie nur ein Ergebnis wollen, könnten Sie LIMIT

SELECT * FROM barcode WHERE `code` = 'abc ' LIMIT 1; 

verwenden exakte Zeichenfolge Dazu passend Sie Collation

SELECT * 
FROM barcode 
WHERE code COLLATE utf8_bin = 'abc'; 
+0

Dies beantwortet nicht das OP - das Problem scheint zu sein, dass sie nur exakte Zeichenfolgenübereinstimmungen haben wollen, einschließlich führender und nachstehender Leerzeichen. Mit 'LIMIT' wird dies nicht erreicht. – Romain

+1

Ich glaube nicht, dass Ihre vorgeschlagene Verwendung von 'COLLATE utf8_general_ci' einen Unterschied machen wird? – eggyal

+0

'COLLATE binary' würde tun – Kaii

2

Sie können mit einem regular expression matching versuchen verwenden:

SELECT * FROM barcode WHERE `code` REGEXP 'abc[[:space:]]' 
+1

Downvoter Pflege, um den Rest von uns zu verstehen, was Sie denken, ist falsch mit dieser Antwort? – eggyal

+0

Ich denke, diese Antwort wurde downvoted, weil 'REGEXP' Indexsuche deaktiviert und immer zu einem vollständigen Tabellenscan führt. Wenn Sie regex * in mysql vermeiden können, sollten Sie es nicht verwenden. – Kaii

0

Sie könnten dies tun:

SELECT * FROM barcode WHERE `code` = 'abc ' 
AND CHAR_LENGTH(`code`)=CHAR_LENGTH('abc '); 
+0

Downvoter Pflege, um den Rest von uns zu verstehen, was Sie denken, ist falsch mit dieser Antwort? – eggyal

+0

Ich denke, diese Antwort wurde downvoted, weil 'WHERE F (x) = F (y)' eine Menge Rechenaufwand verursacht, weil die Funktion für jede Zeile im Ergebnisdatensatz zweimal ausgeführt werden muss. In diesem Fall ist es nicht so schlimm, denn es gibt mindestens eine einfache 'WHERE'-Bedingung. Wenn "F (x) = F (y)" die * einzige * Bedingung ist, würde dies zu einem vollständigen Tabellenscan führen, was Sie vermeiden sollten. – Kaii

7

Es gibt keine andere Lösung dafür. Entweder geben Sie einen einzelnen Vergleich als binary an oder Sie legen die gesamte Datenbankverbindung auf binary fest. (Tun SET NAMES binary, die andere Nebenwirkungen haben können!)

Grundsätzlich dass ‚faul‘ Vergleich ist ein Feature von MySQL, die hart codiert. Um es zu deaktivieren (auf Anfrage!), Können Sie einen binary vergleichen, was Sie anscheinend schon machen. Dies ist kein "Workaround", sondern die eigentliche Lösung.

vom MySQL Manual:

Alle MySQL-Sortierungen sind vom Typ PADSPACE. Das bedeutet, dass alle CHAR und VARCHAR-Werte in MySQL ohne Rücksicht auf irgendwelche Leerzeichen verglichen werden

Natürlich gibt es viele andere Möglichkeiten sind das gleiche Ergebnis aus der Perspektive eines Benutzers zu erreichen, das heißt:

  • WHERE field = 'abc ' AND CHAR_LENGTH(field) = CHAR_LENGTH('abc ')
  • WHERE field REGEXP 'abc[[:space:]]'

Das Problem mit diesen ist, dass sie eff Deaktivieren Sie schnell schnelle Indexsuchen, sodass Ihre Abfrage immer zu einem vollständigen Tabellenscan führt. Mit riesigen Datensätzen, die einen großen Unterschied machen.

Wieder:PADSPACE ist Standard für MySQL [VAR] CHAR Vergleich. Sie können (und sollten) es unter Verwendung von BINARY deaktivieren.Dies ist der Weg, dies zu tun.

-1

Der Satz unmittelbar nach dem von Kaii zitierte eine im Grunde sagt: "verwenden LIKE":

“Comparison” in this context does not include the LIKE pattern-matching operator, for which trailing spaces are significant

und das folgende Beispiel zeigt, dass 'Monty' = 'Monty ' wahr ist, aber nicht 'Monty' LIKE 'Monty '.

Wenn Sie jedoch LIKE verwenden, passen sie von Literalzeichenfolgen mit den '%', '_' oder '\' Zeichen: '%' und '_' Wildcard-Zeichen sind, wird '\' verwendet, um Sequenzen zu entkommen.

+0

schöner Fang. Bei der Verwendung von 'LIKE' sollten jedoch auch die anderen Nebenwirkungen des' LIKE'-Operators beachtet werden. Beispiele: "A" LIKE "a" 'ist wahr," a "LIKE" _ "' ist ebenfalls wahr. Zur Umgehung der Case-Unempfindlichkeit von 'LIKE' bietet das Handbuch eine' LIKE BINARY' -Operation. Und da ist der Kreis geschlossen: 'BINARY' ist der eigentliche Fix. Wenn Sie mir nicht glauben, finden Sie im Handbuch für ['LIKE'] (http://dev.mysql.com/doc/refman/5.0/en/string-comparison-functions.html#operator_like). Der einzige Unterschied zwischen '= BINARY' und' LIKE BINARY' ist, dass 'LIKE' mehr Nebenwirkungen hat. Sorry;) – Kaii

+0

Ok, danke für die zusätzlichen Details. – LeGEC

+0

'" A "wie" a "' hängt von der Sortierung ab, nicht wahr? genau wie '='. Ich war mir des Sonderzeichens "_" jedoch nicht bewusst. Es verkompliziert sicher die Eckfälle. Danke, dass du darauf hingewiesen hast. – LeGEC

0

Ich arbeitete nur auf Fall genau so, wenn LIKE mit Platzhalter (%) verwendet, was zu einem unerwarteten Ergebnis führte. Während der Suche fand ich auch STRCMP(text1, text2) unter String Vergleich Feature von MySQL, die zwei Zeichenfolge vergleicht. Die Verwendung von BINARY mit LIKE löste das Problem für mich.

+2

FYI: Während Ihre Antwort plausibel erscheint, ist sie in der Warteschlange 'Posts niedriger Qualität' erschienen, nachdem sie zum Löschen markiert wurde.Ich vermute, das liegt daran, dass es sich um eine Code-Antwort ohne Erklärung handelt. Um hier klar zu sein, ich habe es nicht markiert, also weiß ich nicht, warum es markiert wurde. Allerdings sehe ich eine Menge Code-Antworten, die nur in dieser Warteschlange angezeigt werden. Daher habe ich mir vorgenommen, ihnen Kommentare hinzuzufügen, damit der Responder dies bemerkt. –

+0

mein schlechtes. Ich sollte eine Erklärung hinzufügen. danke für die Information. –