2012-04-27 4 views
5

ho creato tabella come quella in MySQL:String confrontare esattamente nella query 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 '); 

Poi ho interrogare i dati dalla tabella di codici a barre:

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

Il risultato è:

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

Ma voglio che il set di risultati sia solo 1 record. Ho risolto il problema con:

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

Il risultato è 1 record. Ma sto usando NHibernate con MySQL per generare query dalla tabella di mapping. In modo che come risolvere questo caso?

+0

La prossima volta, guarda come verrà fuori la tua domanda (c'è una finestra di anteprima sotto il tuo campo di testo), e se sembra un disastro, risolvilo :). Utilizza una quantità generosa del tasto '{}' in alto per il codice ..... – Nanne

+1

Puoi fornire i mapping NHibenate e i metodi che utilizzi per generare una query? Perché usi l'SQL nativo con NHibernate. Penso che dovresti usare Criteria API o HQL. –

+1

dai documenti: ["Tutte le regole di confronto MySQL sono di tipo PADSPACE. Ciò significa che tutti i valori CHAR e VARCHAR in MySQL vengono confrontati indipendentemente dagli spazi finali"] (http://dev.mysql.com/doc/refman/ 5.0/en/char.html) – Kaii

risposta

0

Io parto dal presupposto che si desidera un solo risultato, è possibile utilizzare LIMIT

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

Per fare stringa esatta corrispondenza si potrebbe usare Collation

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

Questo non sta rispondendo all'OP: il problema sembra essere che vogliono avere solo corrispondenze di stringa esatte, inclusi spazi iniziali e finali. L'uso di 'LIMIT' non lo raggiunge. – Romain

+1

Non penso che il tuo uso proposto di 'COLLATE utf8_general_ci' farà alcuna differenza? – eggyal

+0

'COLLATE binary' farebbe – Kaii

2

si può provare con un regular expression matching:

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

Assistenza per il downnoter per aiutare il resto di noi a capire cosa pensi sia sbagliato in questa risposta? – eggyal

+0

Immagino che questa risposta sia stata downvoted perché 'REGEXP' disabilita le ricerche nell'indice e risulta sempre in una scansione completa della tabella. Se * puoi evitare regex * in mysql, non dovresti usarlo. – Kaii

0

È possibile effettuare questa operazione:

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

Assistenza per il downnoter per aiutare il resto di noi a capire cosa pensi sia sbagliato in questa risposta? – eggyal

+0

Immagino che questa risposta sia stata downvoted perché 'WHERE F (x) = F (y)' sta causando un sacco di overhead computazionale, perché la funzione deve essere eseguita due volte per ogni riga nel set di dati del risultato. In questo caso non è male, perché esiste almeno una semplice condizione "WHERE". Se 'F (x) = F (y)' era la condizione * only *, risulterebbe in una scansione completa della tabella, che è qualcosa che dovresti evitare. – Kaii

7

Non c'è altra soluzione per questo. O si specifica un confronto singolo come binary o si imposta l'intera connessione al database su binary. (Facendo SET NAMES binary, che può avere altri effetti collaterali!)

In sostanza, che 'pigro' il confronto è una caratteristica di MySQL che è codificato duro. Per disabilitarlo (su richiesta!), È possibile utilizzare un confronto binary, ciò che apparentemente già si fa. Questa non è una "soluzione alternativa" ma la vera soluzione.

dal MySQL Manual:

Tutte le regole di confronto di MySQL sono di tipo PADSPACE. Ciò significa che tutti i valori CHAR e VARCHAR in MySQL vengono confrontate senza considerare gli eventuali spazi finali

Naturalmente ci sono molti altri possiblities per ottenere lo stesso risultato dal punto di vista dell'utente, ossia:

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

Il problema con questi è che eff disabilita automaticamente le ricerche indice rapide, quindi la tua query risulta sempre in una scansione completa della tabella. Con enormi set di dati che fanno una grande differenza.

Ancora:PADSPACE è il valore predefinito per il confronto di MySQL [VAR] CHAR. Puoi (e dovresti) disabilitarlo usando BINARY.Questo è il modo indivo per farlo.

-1

La sentenza subito dopo quello citato da Kaii in pratica dice "usa LIKE":

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

e l'esempio seguente mostra che 'Monty' = 'Monty ' è vero, ma non 'Monty' LIKE 'Monty '.

Tuttavia, se si utilizza LIKE, fate attenzione di stringhe letterali contenenti i '%', '_' o '\' caratteri: '%' e '_' sono caratteri jolly, '\' viene utilizzato per le sequenze di escape.

+0

bella cattura. ma quando si usa 'LIKE' si dovrebbe anche essere consapevoli degli altri effetti collaterali dell'operatore' LIKE'. Esempi: '" A "LIKE" a "' è uguale a vero, '" a "LIKE" _ "' eguaglia anche true. Come soluzione alternativa all'insensibilità alle maiuscole/minuscole di 'LIKE', il manuale offre un'operazione' LIKE BINARY' .. Ed è qui che il cerchio è chiuso: 'BINARY' è la vera soluzione. Se non mi credi, consulta il manuale di ['LIKE'] (http://dev.mysql.com/doc/refman/5.0/en/string-comparison-functions.html#operator_like). L'unica differenza tra '= BINARY' e' LIKE BINARY' è che 'LIKE' ha più effetti collaterali. Spiacente;) – Kaii

+0

Ok, grazie per i dettagli extra. – LeGEC

+0

'" A "LIKE" a "' dipende dalle regole di confronto, vero? proprio come '='. Non ero a conoscenza del carattere speciale "_" ", però. Di certo complica le casse d'angolo. Grazie per la segnalazione. – LeGEC

0

stavo solo lavorando su case così come quando si utilizza LIKE con carattere jolly (%) risultante in un risultato inaspettato. Durante la ricerca ho trovato anche STRCMP(text1, text2) nella funzione di confronto delle stringhe di mysql che confronta due stringhe. comunque usando BINARY con LIKE ho risolto il problema per me.

SELECT * FROM barcode WHERE `code` LIKE BINARY 'abc '; 
+2

Nota: sebbene la tua risposta sia plausibile, è apparsa nella coda dei "post di bassa qualità" dopo essere stata contrassegnata per l'eliminazione.Sospetto che sia perché è una risposta solo in codice senza spiegazione. Per essere chiari qui, non l'ho segnalato, quindi non so perché è stato contrassegnato. Tuttavia vedo un sacco di risposte al solo codice che appaiono in quella coda, quindi ho preso ad aggiungere commenti a loro in modo che il rispondente è a conoscenza di questo. –

+0

il mio male. dovrei aggiungere qualche spiegazione. grazie per avermi fatto sapere. –