Tengo este mensaje de error:
Mensaje 8134, Nivel 16, Estado 1, Línea 1 Divide por cero error encontrado.
¿Cuál es la mejor manera de escribir código SQL para que nunca vuelva a ver este mensaje de error?
Podría hacer cualquiera de los siguientes:
- Agregue una cláusula where para que mi divisor nunca sea cero
O
- Podría agregar una declaración de caso, para que haya un tratamiento especial para cero.
¿Es la mejor manera de usar una NULLIF
cláusula?
¿Hay una mejor manera, o cómo se puede hacer cumplir?
sql
sql-server
sql-server-2005
sql-server-2008
Henrik Staun Poulsen
fuente
fuente
Respuestas:
Para evitar un error de "División por cero", lo hemos programado así:
Pero aquí hay una manera mucho mejor de hacerlo:
Ahora el único problema es recordar el bit NullIf, si uso la tecla "/".
fuente
IsNull
lugar deNullIf
? ¡Inténtalo tú mismo!SELECT Value,1/NullIf(Value,0)FROM(VALUES(0),(5.0),(NULL))x(Value);
¿A menos que por "interrupciones" se refiera a un NULL? Puedes convertir eso a lo que quieras conIsNull
oCoalesce
.SELECT 1 / NULLIF(NULL, 0)
falla, pero es porqueNULLIF()
necesita saber el tipo de datos del primer argumento. Este ejemplo alterada funciona bien:SELECT 1 / NULLIF(CAST(NULL AS INT), 0)
. En la vida real, va a proporcionar una columna de tabla enNULLIF()
lugar de unaNULL
constante. Ya que las columnas de la tabla tienen tipos de datos conocidos, esto también funciona bien:SELECT 1 / NULLIF(SomeNullableColumn, 0) FROM SomeTable
.En caso de que desee devolver cero, en caso de que ocurra un dispositivo cero, puede usar:
Por cada divisor que sea cero, obtendrá un cero en el conjunto de resultados.
fuente
Esta parece ser la mejor solución para mi situación cuando intento abordar la división entre cero, lo que sucede en mis datos.
Suponga que desea calcular las relaciones hombre-mujer para varios clubes escolares, pero descubre que la siguiente consulta falla y emite un error de división por cero cuando intenta calcular la relación para el Club del Señor de los Anillos, que no tiene mujeres :
Puede usar la función
NULLIF
para evitar la división por cero.NULLIF
compara dos expresiones y devuelve nulo si son iguales o la primera expresión de lo contrario.Reescribe la consulta como:
Cualquier número dividido por
NULL
daNULL
, y no se genera ningún error.fuente
select males/(males+females), females/(males+females)
. Esto le dará la distribución porcentual de hombres y mujeres en un club, como 31% hombres, 69% mujeres.También puede hacer esto al comienzo de la consulta:
Entonces, si tiene algo así
100/0
, devolverá NULL. Solo he hecho esto para consultas simples, por lo que no sé cómo afectará a las más largas / complejas.fuente
Al menos puede evitar que la consulta se rompa con un error y regresar
NULL
si hay una división por cero:Sin embargo, NUNCA convertiría esto a Cero
coalesce
como se muestra en esa otra respuesta que obtuvo muchos votos positivos. Esto es completamente incorrecto en un sentido matemático, e incluso es peligroso ya que su aplicación probablemente arrojará resultados incorrectos y engañosos.fuente
EDITAR: Recibo muchos votos negativos sobre esto recientemente ... así que pensé en agregar una nota de que esta respuesta se escribió antes de que la pregunta se sometiera a su edición más reciente, donde el retorno nulo se destacó como una opción ... .que parece muy aceptable. Parte de mi respuesta se dirigió a preocupaciones como la de Edwardo, en los comentarios, que parecía estar abogando por devolver un 0. Este es el caso contra el que estaba criticando.
RESPUESTA: Creo que hay un problema subyacente aquí, que es que la división por 0 no es legal. Es una indicación de que algo está fundamentalmente mal. Si está dividiendo entre cero, está tratando de hacer algo que no tiene sentido matemáticamente, por lo que ninguna respuesta numérica que pueda obtener será válida. (El uso de nulo en este caso es razonable, ya que no es un valor que se utilizará en cálculos matemáticos posteriores).
Entonces, Edwardo pregunta en los comentarios "¿y si el usuario pone un 0?", Y defiende que debería estar bien obtener un 0 a cambio. Si el usuario pone cero en la cantidad, y desea que se devuelva 0 cuando lo hace, entonces debe poner un código en el nivel de reglas de negocio para capturar ese valor y devolver 0 ... no tiene algún caso especial donde la división por 0 = 0.
Esa es una diferencia sutil, pero es importante ... porque la próxima vez que alguien llame a su función y espere que haga lo correcto, y hace algo funky que no es matemáticamente correcto, pero solo maneja el caso particular, tiene un buenas posibilidades de morder a alguien más tarde. Realmente no estás dividiendo por 0 ... solo estás devolviendo una mala respuesta a una mala pregunta.
Imagina que estoy codificando algo y lo arruino. Debería estar leyendo en un valor de escala de medición de radiación, pero en un caso extraño que no anticipé, leí en 0. Luego dejo caer mi valor en su función ... ¡me devuelve un 0! ¡Hurra, no hay radiación! Excepto que realmente está allí y es solo que estaba pasando un mal valor ... pero no tengo idea. Quiero que la división arroje el error porque es la bandera de que algo está mal.
fuente
Al atrapar el cero con un nullif (), el nulo resultante con un isnull () puede evitar su error de división por cero.
fuente
Reemplazar "dividir por cero" con cero es controvertido, pero tampoco es la única opción. En algunos casos, reemplazar con 1 es (razonablemente) apropiado. A menudo me encuentro usando
cuando estoy viendo cambios en los puntajes / recuentos, y quiero establecer el valor predeterminado en 1 si no tengo datos. Por ejemplo
La mayoría de las veces, he calculado esta relación en otro lugar (sobre todo porque puede arrojar algunos factores de ajuste muy grandes para denominadores bajos. En este caso, normalmente el control para OldSampleScore es mayor que un umbral; lo que luego excluye cero Pero a veces el 'pirateo' es apropiado.
fuente
Escribí una función hace un tiempo para manejarla para mis procedimientos almacenados :
fuente
Divisor
a ser distinto de cerofuente
Para actualizar SQLs:
fuente
No existe una configuración global mágica "desactivar división por 0 excepciones". La operación tiene que lanzar, ya que el significado matemático de x / 0 es diferente del significado NULL, por lo que no puede devolver NULL. Supongo que se está ocupando de lo obvio y sus consultas tienen condiciones que deberían eliminar los registros con el divisor 0 y nunca evaluar la división. El 'problema' habitual es que la mayoría de los desarrolladores esperan que SQL se comporte como lenguajes de procedimiento y ofrezca un cortocircuito de operador lógico, pero NO . Le recomiendo que lea este artículo: http://www.sqlmag.com/Articles/ArticleID/9148/pg/2/2.html
fuente
Aquí hay una situación en la que puedes dividir por cero. La regla de negocio es que para calcular los turnos de inventario, usted toma el costo de los bienes vendidos por un período, lo anualiza. Después de tener el número anualizado, se divide por el inventario promedio del período.
Estoy considerando calcular la cantidad de vueltas de inventario que ocurren en un período de tres meses. He calculado que he vendido el costo de los bienes durante el período de tres meses de $ 1,000. La tasa anual de ventas es de $ 4,000 ($ 1,000 / 3) * 12. El inventario inicial es 0. El inventario final es 0. Mi inventario promedio ahora es 0. Tengo ventas de $ 4000 por año y no tengo inventario. Esto produce un número infinito de vueltas. Esto significa que todo mi inventario está siendo convertido y comprado por los clientes.
Esta es una regla comercial de cómo calcular los giros de inventario.
fuente
fuente
Filtre los datos utilizando una cláusula where para que no obtenga valores 0.
fuente
A veces, 0 puede no ser apropiado, pero a veces 1 tampoco es apropiado. A veces, un salto de 0 a 100,000,000 descrito como 1 o 100 por ciento de cambio también puede ser engañoso. 100,000,000 por ciento podría ser apropiado en ese escenario. Depende de qué tipo de conclusiones pretendes sacar en función de los porcentajes o proporciones.
Por ejemplo, un artículo de venta muy pequeña que pasa de 2-4 vendido y un artículo de venta muy grande que cambia de 1,000,000 a 2,000,000 vendido podría significar cosas muy diferentes para un analista o para la administración, pero ambos aparecerían como 100% o 1 cambio.
Puede ser más fácil aislar valores NULL que recorrer un conjunto de filas 0% o 100% mezcladas con datos legítimos. A menudo, un 0 en el denominador puede indicar un error o un valor perdido, y es posible que no desee completar un valor arbitrario solo para que su conjunto de datos se vea ordenado.
fuente
Así es como lo arreglé:
IIF (ValorA! = 0, Total / ValorA, 0)
Se puede envolver en una actualización:
SET Pct = IIF (ValorA! = 0, Total / ValorA, 0)
O en un selecto:
SELECT IIF (ValueA! = 0, Total / ValueA, 0) AS Pct FROM Tablename;
Pensamientos?
fuente
Puede manejar el error de manera apropiada cuando se propaga nuevamente al programa de llamada (o ignorarlo si eso es lo que desea). En C #, cualquier error que ocurra en SQL arrojará una excepción que puedo detectar y luego manejar en mi código, al igual que cualquier otro error.
Estoy de acuerdo con Beska en que no quieres ocultar el error. Es posible que no esté tratando con un reactor nuclear, pero ocultar errores en general es una mala práctica de programación. Esta es una de las razones por las que los lenguajes de programación más modernos implementan el manejo estructurado de excepciones para desacoplar el valor de retorno real con un código de error / estado. Esto es especialmente cierto cuando estás haciendo matemáticas. El mayor problema es que no puede distinguir entre un 0 calculado correctamente o un 0 como resultado de un error. En cambio, cualquier valor devuelto es el valor calculado y, si algo sale mal, se genera una excepción. Esto, por supuesto, diferirá según cómo esté accediendo a la base de datos y qué idioma está utilizando, pero siempre debería poder recibir un mensaje de error con el que pueda lidiar.
fuente
Use
NULLIF(exp,0)
pero de esta manera -NULLIF(ISNULL(exp,0),0)
NULLIF(exp,0)
se rompe si exp esnull
peroNULLIF(ISNULL(exp,0),0)
no se romperáfuente