2010-04-02 12 views
17

Ho riscontrato un problema introducendo colonne in virgola mobile nello schema del database MySQL che i confronti su valori in virgola mobile non restituiscono sempre i risultati corretti.Problemi di confronto in virgola mobile di MySQL

1-50,12
2-34,57
3-12,75
4 - ... (il resto tutti a meno di 12,00)

SELECT COUNT(*) FROM `users` WHERE `points` > "12.75" 

Questo mi restituisce "3".

Ho letto che il confronto dei valori in virgola mobile in MySQL è una cattiva idea e il tipo decimale è l'opzione migliore.

Ho qualche speranza di andare avanti con il tipo float e ottenere il confronto per funzionare correttamente?

+0

Quali tipi di letterali sono racchiusi tra virgolette doppie in SQL? – Joey

+1

Sfortunatamente, MySQL consente alle virgolette doppie di agire come virgolette singole per impostazione predefinita. Questa funzione può essere disattivata con l'opzione 'ANSI_QUOTES', che farà in modo che si riferiscano agli identificatori come per lo standard ANSI SQL (come i backtick non standard nella query precedente). – bobince

+1

12.75 è esattamente rappresentabile in binario (1100.11), quindi non vedo come passa il test "> 12.75". Sei sicuro che non ci siano altri punti> 12.75 nella tua lista? –

risposta

23

Si nota il problema di seguito?

CREATE TABLE a (num float); 

INSERT INTO a VALUES (50.12); 
INSERT INTO a VALUES (34.57); 
INSERT INTO a VALUES (12.75); 
INSERT INTO a VALUES (11.22); 
INSERT INTO a VALUES (10.46); 
INSERT INTO a VALUES (9.35); 
INSERT INTO a VALUES (8.55); 
INSERT INTO a VALUES (7.23); 
INSERT INTO a VALUES (6.53); 
INSERT INTO a VALUES (5.15); 
INSERT INTO a VALUES (4.01); 

SELECT SUM(num) FROM a; 
+-----------------+ 
| SUM(num)  | 
+-----------------+ 
| 159.94000005722 | 
+-----------------+ 

C'è uno spread 0.00000005722 in più tra alcune di queste righe. Pertanto alcuni di questi valori restituiranno false se confrontati con il valore con cui sono stati inizializzati.

Per evitare problemi con aritmetica in virgola mobile e confronti, è necessario utilizzare il tipo di dati DECIMAL:

ALTER TABLE a MODIFY num DECIMAL(6,2); 

SELECT SUM(num) FROM a; 
+----------+ 
| SUM(num) | 
+----------+ 
| 159.94 | 
+----------+ 
1 row in set (0.00 sec) 
+0

Hey Daniel! Grazie. Sto pensando di convertire il mio tipo di colonna in DECIMALE. –

+1

@Sharief: se la conversione in 'DECIAML' è impossibile, l'unica opzione che vedo è di consentire una certa tolleranza per i confronti in virgola mobile, in modo tale da poter scrivere la query come segue:' SELECT COUNT (*) FROM users WHERE points> (12.75 + 0.001); '... Tuttavia se la precisione è fondamentale, il punto fisso' DECIMAL' è la strada da percorrere. Un'altra alternativa a 'DECIMAL' potrebbe essere l'utilizzo di un valore intero scalato per rappresentare i tuoi valori in termini di centesimi:' 5012' invece di '50.12'. Ci possono essere alcune situazioni in cui questo potrebbe essere appropriato. –

+0

Ho provato ad aggiungere già la tolleranza, esattamente come hai detto, anche se i risultati non sono mai stati coerenti. –

1

È un punto mobile, quindi qual è il problema? 3 potrebbe essere il risultato corretto, dipende da cosa il database pensa a 12.75. È 12,75 o solo un po 'di più?

Utilizzare DECIMALE se si desidera ottenere i numeri esatti.

+0

Ciao Frank, puoi approfondire cosa intendi per "cosa pensa il database di 12.75". Devo essere nei guai se provo a confrontare un valore di precisione a due cifre con una precisione a tre cifre. Come ... SELECT COUNT (*) DAGLI utenti 'DOVE' punti'> "12.751" –

+0

@ShariefShaik Penso che Decimal dovrebbe risolvere il caso, da quello che altri utenti sperimentano. – gumuruh

1

C'è un problema con il confronto di float per l'uguaglianza. Questo potrebbe dare risultati imprevedibili. Ciò è dovuto all'implementazione interna dell'aritmetica in virgola mobile.

0

Confronto di un numero con una stringa?

2

ho fatto affrontare il problema simile una volta. Converti il ​​campo 'float' in 'decimal'. Risolverà definitivamente il problema.

+0

Ho pensato che utilizzando la lunghezza fissa precisa del float ho già risolto il problema, quindi non ?? per esempio; Definisco float (4,2). E poi ho memorizzato il valore di 12.50, E POI ho provato a confrontarlo con l'istruzione "> 12.50". Non fallirebbe ancora? – gumuruh

1

faccio questo

WHERE abs(value - 12.75)<0.001 

Ma sono d'accordo, qualsiasi lingua può confrontare galleggiare uguaglianza e se i valori memorizzati è uguale a numeri esatti è stato inserito valori, non ci dovrebbe essere alcun problema

con solo un paio di decimali e valori di corrispondenza esatti, errori di precisione non sembrano un ovvio motivo per tali disallineamenti in MySQL

Problemi correlati