2013-03-30 12 views
21

supporre l'input dell'utentePerché MySQL restituisce righe che apparentemente non corrispondono alla clausola WHERE?

mysite.com/profile?identity=1 
mysite.com/profile?identity=dinodsja 
mysite.com/profile?identity=1a 

ottenere il valore

$identity = $_GET['identity']; // identity can be user_id or user_name 

e ho un semplice query di selezione:

SELECT * FROM lb_users WHERE (user_id = 'dinodsja' OR user_name = 'dinodsja') AND user_status = 1 

e funziona benissimo. ma il problema è:

SELECT * FROM lb_users WHERE (user_id = '1a' OR user_name = '1a') AND user_status = 1 

quando eseguo questa query restituisce anche il risultato senza soddisfare la condizione.

Struttura della tabella:

user_id  bigint(25) 
user_name varchar(50)  utf8_general_ci 

enter image description here

**

-> Is this a MySQL Bug ? 
-> How can we avoid this ? 
-> What will be the query ? 

**

+0

cos'è BIGING? – Satya

+0

puoi pubblicare la struttura della tabella –

+0

@Satya è BIGINT – jeremy

risposta

24

mi ricordo avendo un problema simile tempo fa.

Primo sfondo: Questo è non un errore. In realtà è una caratteristica. Ok, è uno che potrebbe portare a un comportamento così inaspettato, ma MySQL è quindi molto tollerante con te. input dell'utente, rispettive domande prescelte:

mysql> SELECT 'a' = 'a '; 
     -> 1 
mysql> SELECT 'A' = 'a'; 
     -> 1 

Pertanto, con implicit type conversion, il risultato di, per esempio, '1a' in intero è 1, ma anche:

mysql> SELECT 0 = 'x6'; 
     -> 1 
mysql> SELECT 1 = ' 1'; 
     -> 1 
mysql> SELECT 1 = ' 1a'; 
     -> 1 

Questa funzione è implementata anche in altri non staticamente lingue digitate PHP, per esempio, chiama questo type juggling.Vedere la PHP String conversion rules e questo esempio dalla documentazione:

<?php 
    $foo = "0";      // $foo is string (ASCII 48) 
    $foo += 2;      // $foo is now an integer (2) 
    $foo = $foo + 1.3;    // $foo is now a float (3.3) 
    $foo = 5 + "10 Little Piggies"; // $foo is integer (15) 
    $foo = 5 + "10 Small Pigs";  // $foo is integer (15) 
?> 

Vedi JavaScript:

<script> 
    document.write(parseInt("40 years") + "<br>"); 
</script> 

=> 40 

Tuttavia, la soluzione al vostro problema è piuttosto semplice: basta lanciare il numero intero a un char e fare il confronto poi :

mysql> SELECT * FROM lb_users WHERE (CAST(user_id AS CHAR) = '1' OR user_name = '1') 
     -> 1 
mysql> SELECT * FROM lb_users WHERE (CAST(user_id AS CHAR) = '1a' OR user_name = '1a') 
     -> 0 
mysql> SELECT * FROM lb_users WHERE (CAST(user_id AS CHAR) = 'dinodsja' OR user_name = 'dinodsja') 
     -> 1 

ho fatto un violino per tutti di provarlo: http://sqlfiddle.com/#!2/c2835/14/0

Speranza che aiuta,

-Hannes

+4

Non sono d'accordo. Questo ** è ** un bug, non una funzionalità. –

+1

E non sono d'accordo. Questa è una funzionalità implementata in varie lingue. Ad esempio in PHP questo è chiamato tipo giocoleria. Per l'evidenziazione della sintassi modifico la mia risposta e aggiungo un esempio di codice. Penso che sia molto positivo che questi linguaggi siano coerenti tra loro, in quanto vengono spesso utilizzati nello stesso contesto. –

+7

Questo potrebbe essere vero per PHP (o altri linguaggi tipizzati debolmente), ma SQL è un linguaggio fortemente tipizzato (come Java) e questo comportamento non solo è completamente inaspettato ma viola anche lo standard SQL che afferma chiaramente che deve essere lanciata un'eccezione in tal caso –

31

La ragione di ciò è perché il tipo di dati della colonna è user_ID intero.

MySQL silenziosamente gocce qualsiasi trascinamentoNON Numero (e tutto ciò che segue all'interno) nel valore ed è per questo 1a è uguale 1 dal a sarà rimuovere il valore.

+3

ok. grazie. quindi possiamo evitarlo. wat sarà la domanda? – Dino

+0

@DBK puoi gestire il valore di controllo in 'PHP'. –

+0

è un input dell'utente per il profilo. l'utente può fornire user_id o user_name. quindi l'input è valido. ma nessun dato. – Dino

0

secondo il vostro messaggio precedente

suo un input dell'utente per il profilo. l'utente può fornire user_id o user_name. quindi l'input è valido. ma nessun dato. - DBK 30 marzo alle 6:42

Si consiglia di provare per vedere se è un numero intero e cercare l'ID utente solo se è un numero intero. È davvero più una soluzione alternativa per mySQL che non gestisce un confronto da STRING a INT, ma dovrebbe funzionare.

declare @InputVar varchar(10) 
set @InputVar = '1a' 

SELECT * 
FROM lb_users 
WHERE 
    (case when isnumeric(@InputVar) = 1 then 
    case when (user_id = @InputVar OR user_name = @InputVar) then 1 else 0 end 
    else 
    case when user_name = @InputVar then 1 else 0 end 
    end =1) 
And 
    user_status = 1 
0

Quando si tratta di stringhe userei 'LIKE' invece che '=' per evitare questo silenzio follia tipo di conversione. LIKE è fatto per funzionare con le stringhe, quindi perché non usarlo.

0
SELECT * FROM lb_users WHERE (user_id = '1a' OR user_name = '1a') AND user_status = 1 

si ottiene 1 risultato se si cambia '1 bis' per 1 bis si ottiene questo:

# 1064 - Hai un errore nella sintassi SQL; controllare il manuale che corrisponde alla versione del server MySQL per la sintassi diritto di utilizzare vicino a '1a LIMIT 0, 30' at line 1

Questo non è un bug, dare un'occhiata a http://dev.mysql.com/doc/refman/5.0/en/where-optimizations.html

speranza che questo aiuti

0

Penso che non è possibile duplicare una chiave primaria e un ID, verifico che uno e vengo con una corsa data..did si imposta l'user_id con i suoi attributi come:

user_id bigint(50) auto_increment primary key 

questo non è un errore mysql.

Problemi correlati