2010-04-02 24 views
17

Encontré un problema al introducir columnas de punto flotante en el esquema de la base de datos MySQL que las comparaciones en valores de coma flotante no siempre arrojan los resultados correctos.Problemas de comparación de punto flotante MySQL

1 - 50.12
2 - 34.57
3 - 12.75
4 - ... (rest a menos de 12,00)

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

Esto me devuelve "3".

He leído que las comparaciones de valores de coma flotante en MySQL son una mala idea y el tipo decimal es la mejor opción.

¿Tengo alguna esperanza de seguir adelante con el tipo de letra flotante y hacer que las comparaciones funcionen correctamente?

+0

¿Qué tipos de literales están entre comillas dobles en SQL? – Joey

+1

Desafortunadamente, MySQL permite que las comillas dobles actúen como comillas simples de forma predeterminada. Esta característica se puede desactivar con la opción 'ANSI_QUOTES', que hará que se refieran a los identificadores según el estándar ANSI SQL (como los backticks no estándar en la consulta anterior). – bobince

+1

12.75 es exactamente representable en binario (1100.11), por lo que no veo cómo pasa la prueba "> 12.75". ¿Estás seguro de que no hay otro punto> 12.75 en tu lista? –

Respuesta

23

¿Observa el problema a continuación?

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 | 
+-----------------+ 

Hay un espacio extra 0.00000005722 entre algunas de esas filas. Por lo tanto, algunos de esos valores devolverán falso en comparación con el valor con el que se inicializaron.

Para evitar problemas con la aritmética de punto flotante y las comparaciones, se debe utilizar el tipo de datos 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

¡Hola, Daniel! Gracias. Estoy considerando convertir mi tipo de columna a DECIMAL. –

+1

@Sharief: si la conversión a 'DECIAML' es imposible, la única opción que veo es permitir cierta tolerancia para las comparaciones de coma flotante, de modo que pueda escribir su consulta de la siguiente manera:' SELECT COUNT (*) FROM usuarios WHERE points> (12.75 + 0.001); '... Sin embargo, si la precisión es primordial, el punto fijo' DECIMAL' es el camino a seguir. Otra alternativa a 'DECIMAL' podría ser usar un valor entero escalado para representar sus valores en términos de centésimas:' 5012' en vez de '50.12'. Puede haber algunas situaciones donde esto podría ser apropiado. –

+0

Intenté agregar la tolerancia, exactamente como lo mencionaste, incluso entonces los resultados nunca fueron consistentes. –

1

Es un punto flotante, ¿cuál es el problema? 3 podría ser el resultado correcto, depende de lo que la base de datos piensa acerca de 12.75. ¿Es 12.75 o solo un poco más?

Usa DECIMAL si quieres números exactos.

+0

Hola Frank, ¿puedes explicar lo que quieres decir con "lo que la base de datos piensa acerca de 12.75". Debo estar en problemas si trato de comparar un valor de precisión de dos dígitos con una precisión de tres dígitos. Me gusta ... SELECCIONE LA CUENTA (*) DE 'users' DONDE' points'> "12.751" –

+0

@ShariefShaik Creo que Decimal debería resolver ese caso, de lo que otras experiencias de usuario. – gumuruh

1

Hay un problema con la comparación de flotadores para la igualdad. Esto puede dar resultados imprevistos. Esto se debe a la implementación interna de aritmética de coma flotante.

0

Comparando un número con una cadena?

2

hice enfrentarse al problema similar una vez. Convierta el campo 'flotante' en 'decimal'. Definitivamente resolverá el problema.

+0

Pensé que al usar una longitud fija fija de flotación ya se resolvió el problema, por lo que no ?? por ejemplo; yo defino float (4,2). Y luego almacené el valor de 12.50, Y LUEGO trato de compararlo con la declaración "> 12.50". ¿No fallaría aún? – gumuruh

1

hago esto

WHERE abs(value - 12.75)<0.001 

pero estoy de acuerdo, cualquier idioma puede comparar flotar igualdad y si los valores almacenados es igual a los números exactos que ha insertado valores, no debería haber ningún problema

con sólo un par de decimales y valores coincidentes exactos, los errores de precisión no suenan como una razón obvia para tales desajustes en MySQL

Cuestiones relacionadas