Eu tenho esta mensagem de erro:
Msg 8134, Nível 16, Estado 1, Linha 1 Erro de divisão por zero encontrado.
Qual é a melhor maneira de escrever código SQL para que eu nunca mais veja essa mensagem de erro?
Eu poderia fazer um dos seguintes:
- Adicione uma cláusula where para que meu divisor nunca seja zero
Ou
- Eu poderia adicionar uma declaração de caso, para que haja um tratamento especial para zero.
É a melhor maneira de usar uma NULLIF
cláusula?
Existe uma maneira melhor ou como isso pode ser aplicado?
sql
sql-server
sql-server-2005
sql-server-2008
Henrik Staun Poulsen
fonte
fonte
Respostas:
Para evitar um erro "Divisão por zero", nós o programamos assim:
Mas aqui está uma maneira muito melhor de fazer isso:
Agora, o único problema é lembrar o bit NullIf, se eu usar a tecla "/".
fonte
IsNull
vez deNullIf
? Tente você mesmo!SELECT Value,1/NullIf(Value,0)FROM(VALUES(0),(5.0),(NULL))x(Value);
A menos que por "quebras" você queira dizer retorne um NULL? Você pode converter isso para o que quiser comIsNull
ouCoalesce
.SELECT 1 / NULLIF(NULL, 0)
falha, mas é porqueNULLIF()
precisa conhecer o tipo de dados do primeiro argumento. Este exemplo alterado funciona bem:SELECT 1 / NULLIF(CAST(NULL AS INT), 0)
. Na vida real, você fornecerá uma coluna da tabela emNULLIF()
vez de umaNULL
constante. Desde colunas da tabela possuem tipos de dados conhecidos, isso também funciona bem:SELECT 1 / NULLIF(SomeNullableColumn, 0) FROM SomeTable
.Caso deseje retornar zero, caso ocorra um desvio zero, você pode usar:
Para cada divisor que é zero, você receberá um zero no conjunto de resultados.
fonte
Essa parecia ser a melhor correção para minha situação ao tentar resolver a divisão por zero, o que acontece nos meus dados.
Suponha que você queira calcular as proporções homem-mulher para vários clubes da escola, mas descobre que a consulta a seguir falha e emite um erro de divisão por zero quando tenta calcular a proporção para o Clube do Senhor dos Anéis, que não tem mulheres :
Você pode usar a função
NULLIF
para evitar a divisão por zero.NULLIF
compara duas expressões e retorna nulo se forem iguais ou a primeira expressão de outra forma.Reescreva a consulta como:
Qualquer número dividido por
NULL
doaNULL
, e nenhum erro é gerado.fonte
select males/(males+females), females/(males+females)
. Isso fornecerá a distribuição percentual de homens e mulheres em um clube, como 31% homens e 69% mulheres.Você também pode fazer isso no início da consulta:
Portanto, se você tiver algo parecido
100/0
, retornará NULL. Eu fiz isso apenas para consultas simples, então não sei como isso afetará as mais longas / complexas.fonte
Você pode pelo menos impedir que a consulta seja interrompida por um erro e retornar
NULL
se houver uma divisão por zero:No entanto, NUNCA converteria isso em Zero,
coalesce
como mostra a outra resposta que recebeu muitos votos. Isso é completamente errado no sentido matemático e é até perigoso, pois seu aplicativo provavelmente retornará resultados errados e enganosos.fonte
Edição: Estou recebendo muitas votações negativas sobre isso recentemente ... então pensei em adicionar uma nota de que esta resposta foi escrita antes da pergunta ser submetida à edição mais recente, onde retornar nulo foi destacado como uma opção .. .que parece muito aceitável. Parte da minha resposta foi dirigida a preocupações como a de Edwardo, nos comentários, que pareciam estar defendendo o retorno de um 0. É esse o caso contra o qual eu estava reclamando.
RESPOSTA: Eu acho que há uma questão subjacente aqui, que é que a divisão por 0 não é legal. É uma indicação de que algo está errado fundamentalmente. Se você está dividindo por zero, está tentando fazer algo que não faz sentido matematicamente, para que nenhuma resposta numérica que você possa obter seja válida. (O uso de null neste caso é razoável, pois não é um valor que será usado em cálculos matemáticos posteriores).
Então, Edwardo pergunta nos comentários "e se o usuário colocar um 0?", E ele defende que não há problema em obter um 0 em troca. Se o usuário colocar zero no valor e você desejar 0 retornado quando fizer isso, deverá inserir um código no nível das regras de negócios para capturar esse valor e retornar 0 ... não terá algum caso especial em que a divisão por 0 = 0
Essa é uma diferença sutil, mas é importante ... porque da próxima vez que alguém chamar sua função e esperar que ela faça a coisa certa, faça algo descolado que não seja matematicamente correto, mas que lide apenas com o caso específico, boa chance de morder alguém mais tarde. Você não está realmente dividindo por 0 ... está apenas retornando uma resposta ruim para uma pergunta ruim.
Imagine que estou codificando algo e estrago tudo. Eu deveria estar lendo em um valor de escala de medição de radiação, mas em um caso estranho que não previ, li em 0. Depois, coloco meu valor em sua função ... você me retorna 0! Viva, sem radiação! Só que está realmente lá e é que eu estava passando com um valor ruim ... mas não faço ideia. Quero que a divisão gere o erro, porque é a bandeira de que algo está errado.
fonte
Ao capturar o zero com um nullif (), o nulo resultante com um isnull (), você pode contornar sua divisão por erro zero.
fonte
Substituir "dividir por zero" por zero é controverso - mas também não é a única opção. Em alguns casos, a substituição por 1 é (razoavelmente) apropriada. Costumo me encontrar usando
quando estou observando mudanças nas pontuações / contagens e quero usar como padrão 1 se não tiver dados. Por exemplo
Na maioria das vezes, na verdade, eu calculei essa proporção em algum outro lugar (principalmente porque pode gerar alguns fatores de ajuste muito grandes para denominadores baixos. Nesse caso, eu normalmente controlaria o OldSampleScore é maior que um limite; o que então impede zero Mas às vezes o 'hack' é apropriado.
fonte
Escrevi uma função há algum tempo para lidar com ela nos meus procedimentos armazenados :
fonte
Divisor
a ser diferente de zerofonte
Para SQLs de atualização:
fonte
Não existe uma configuração mágica global 'desativar divisão por 0 exceções'. A operação deve ser lançada, pois o significado matemático de x / 0 é diferente do significado NULL, portanto, não pode retornar NULL. Suponho que você esteja cuidando do óbvio e que suas consultas tenham condições que devem eliminar os registros com o divisor 0 e nunca avaliar a divisão. A 'pegadinha' usual é que a maioria dos desenvolvedores espera que o SQL se comporte como linguagens procedurais e ofereça um curto-circuito lógico ao operador, mas NÃO . Eu recomendo que você leia este artigo: http://www.sqlmag.com/Articles/ArticleID/9148/pg/2/2.html
fonte
Aqui está uma situação em que você pode dividir por zero. A regra de negócios é que, para calcular as rotações de estoque, você tome o custo dos produtos vendidos por um período, anualize-o. Depois de ter o número anualizado, você divide pelo estoque médio do período.
Estou pensando em calcular o número de giros de estoque que ocorrem em um período de três meses. Calculei que tenho o Custo dos produtos vendidos durante o período de três meses de US $ 1.000. A taxa anual de vendas é de US $ 4.000 (US $ 1.000 / 3) * 12. O estoque inicial é 0. O estoque final é 0. Meu estoque médio agora é 0. Tenho vendas de US $ 4000 por ano e nenhum estoque. Isso produz um número infinito de turnos. Isso significa que todo o meu inventário está sendo convertido e comprado pelos clientes.
Esta é uma regra comercial de como calcular as rotações de estoque.
fonte
fonte
Filtre os dados usando uma cláusula where para que você não obtenha 0 valores.
fonte
Às vezes, 0 pode não ser apropriado, mas às vezes 1 também não é apropriado. Às vezes, um salto de 0 a 100.000.000 descrito como alteração de 1 ou 100% também pode ser enganoso. 100.000.000 por cento podem ser apropriados nesse cenário. Depende de que tipo de conclusões você pretende tirar com base nas porcentagens ou proporções.
Por exemplo, um item de venda muito pequena que passa de 2 a 4 vendidos e um item de venda muito grande que muda de 1.000.000 para 2.000.000 vendidos pode significar coisas muito diferentes para um analista ou para a gerência, mas ambos seriam 100% ou 1. mudança.
Pode ser mais fácil isolar valores NULL do que vasculhar um monte de 0% ou 100% de linhas misturadas com dados legítimos. Freqüentemente, um 0 no denominador pode indicar um erro ou valor ausente, e talvez você não queira apenas preencher um valor arbitrário apenas para tornar seu conjunto de dados organizado.
fonte
Foi assim que eu consertei:
IIF (ValorA! = 0, Total / ValorA, 0)
Pode ser agrupado em uma atualização:
SET Pct = IIF (ValorA! = 0, Total / ValorA, 0)
Ou em uma seleção:
SELECT IIF (ValorA! = 0, Total / ValorA, 0) AS Pct FROM Nome da tabela;
Pensamentos?
fonte
Você pode manipular o erro adequadamente quando ele se propaga de volta ao programa de chamada (ou ignorá-lo, se é isso que você deseja). No C #, qualquer erro que ocorra no SQL lançará uma exceção que eu posso capturar e depois manipular no meu código, como qualquer outro erro.
Concordo com Beska no sentido de que você não deseja ocultar o erro. Você pode não estar lidando com um reator nuclear, mas esconder erros em geral é uma prática ruim de programação. Essa é uma das razões pelas quais as linguagens de programação mais modernas implementam o tratamento de exceções estruturadas para dissociar o valor de retorno real com um código de erro / status. Isto é especialmente verdade quando você está fazendo contas. O maior problema é que você não pode distinguir entre um 0 computado corretamente sendo retornado ou um 0 como resultado de um erro. Em vez disso, qualquer valor retornado é o valor calculado e, se algo der errado, uma exceção será lançada. Obviamente, isso será diferente dependendo de como você está acessando o banco de dados e qual idioma está usando, mas você sempre deve receber uma mensagem de erro com a qual pode lidar.
fonte
Use
NULLIF(exp,0)
mas desta maneira -NULLIF(ISNULL(exp,0),0)
NULLIF(exp,0)
quebra se exp é,null
masNULLIF(ISNULL(exp,0),0)
não vai quebrarfonte