Hen*_*sen 339 sql sql-server sql-server-2005 sql-server-2008
我有这个错误消息:
Msg 8134,Level 16,State 1,Line 1遇到零误差.
编写SQL代码的最佳方法是什么,以便我再也不会看到此错误消息?
我可以做以下任何一种情况:
要么
是使用NULLIF
条款的最佳方式吗?
有没有更好的方法,或者如何实施?
Hen*_*sen 602
为了避免"除零"错误,我们将其编程为:
Select Case when divisor=0 then null
Else dividend / divisor
End ,,,
Run Code Online (Sandbox Code Playgroud)
但这是一个更好的方法:
Select dividend / NULLIF(divisor, 0) ...
Run Code Online (Sandbox Code Playgroud)
现在唯一的问题是记住NullIf位,如果我使用"/"键.
Tob*_*han 169
如果你想返回零,万一发生零分割,你可以使用:
SELECT COALESCE(dividend / NULLIF(divisor,0), 0) FROM sometable
Run Code Online (Sandbox Code Playgroud)
对于每个除数为零,您将在结果集中得到零.
小智 64
假设您想要计算各种学校俱乐部的男女比例,但是您发现以下查询失败并在尝试计算指环王俱乐部的比率时发出除零错误,该俱乐部没有女性:
SELECT club_id, males, females, males/females AS ratio
FROM school_clubs;
Run Code Online (Sandbox Code Playgroud)
您可以使用该功能NULLIF
来避免被零除.NULLIF
比较两个表达式,如果相等则返回null,否则返回第一个表达式.
将查询重写为:
SELECT club_id, males, females, males/NULLIF(females, 0) AS ratio
FROM school_clubs;
Run Code Online (Sandbox Code Playgroud)
任何数字除以NULL
给定NULL
,不会产生错误.
小智 43
您也可以在查询开头执行此操作:
SET ARITHABORT OFF
SET ANSI_WARNINGS OFF
Run Code Online (Sandbox Code Playgroud)
所以如果你有类似的东西100/0
会返回NULL.我只是为简单的查询做了这个,所以我不知道它会如何影响更长/更复杂的查询.
SQL*_*ice 33
您至少可以阻止查询中断错误,NULL
如果存在除以零则返回:
SELECT a / NULLIF(b, 0) FROM t
Run Code Online (Sandbox Code Playgroud)
但是,我永远不会将其转换为零,coalesce
就像在其他答案中显示的那样得到了很多赞成.这在数学意义上是完全错误的,甚至是危险的,因为您的应用程序可能会返回错误和误导性的结果.
Bes*_*ska 32
编辑:我最近得到了很多关于这个... ...所以我想我只是添加一个注释,这个答案是在问题进行之前编写的,这是最近的编辑,其中返回null被突出显示为一个选项.. .这似乎非常可以接受.我的一些答案是针对爱德华的关注,在评论中,似乎主张回归0.这就是我所反对的情况.
答案:我认为这里存在一个潜在的问题,即除以0是不合法的.这表明某些事情是错误的.如果你除以零,你就会尝试做一些数学上没有意义的事情,所以你得到的数字答案都不会有效.(在这种情况下使用null是合理的,因为它不是将在以后的数学计算中使用的值).
所以Edwardo在评论中询问"如果用户输入0怎么办?",他主张应该可以获得0作为回报.如果用户在金额中加零,并且你希望在他们这样做时返回0,那么你应该在业务规则级别放入代码来捕获该值并返回0 ...没有一些特殊情况,除以0 = 0.
这是一个微妙的区别,但它很重要...因为下次有人调用你的函数并期望它做正确的事情,并且它做了一些在数学上不正确的时髦,但只是处理特定的边缘情况它有一个以后咬人的好机会.你真的没有被0分开......你只是回答了一个糟糕的问题.
想象一下,我正在编写一些东西,我搞砸了.我应该在辐射测量比例值中读取,但在一个奇怪的边缘情况下我没有预料到,我在0中读到.然后我将我的价值放入你的功能......你给我一个0!华友世纪,没有辐射!除了它真的存在,只是我传递了一个不好的价值......但我不知道.我希望分区抛出错误,因为它是错误的标志.
小智 26
SELECT Dividend / ISNULL(NULLIF(Divisor,0), 1) AS Result from table
Run Code Online (Sandbox Code Playgroud)
通过使用nullif()捕获零,然后使用isnull()得到的null可以绕过除以零的错误.
小智 10
用零除"零除"是有争议的 - 但它也不是唯一的选择.在某些情况下,替换为1是(合理地)合适的.我经常发现自己在使用
ISNULL(Numerator/NULLIF(Divisor,0),1)
Run Code Online (Sandbox Code Playgroud)
当我看分数/计数的变化时,如果我没有数据则想要默认为1.例如
NewScore = OldScore * ISNULL(NewSampleScore/NULLIF(OldSampleScore,0),1)
Run Code Online (Sandbox Code Playgroud)
我经常在其他地方计算这个比例(尤其是因为它可以为低分母投入一些非常大的调整因子.在这种情况下,我通常会控制OldSampleScore大于阈值;然后排除零但有时候"黑客"是合适的.
我一段时间后写了一个函数来处理我的存储过程:
print 'Creating safeDivide Stored Proc ...'
go
if exists (select * from dbo.sysobjects where name = 'safeDivide') drop function safeDivide;
go
create function dbo.safeDivide( @Numerator decimal(38,19), @divisor decimal(39,19))
returns decimal(38,19)
begin
-- **************************************************************************
-- Procedure: safeDivide()
-- Author: Ron Savage, Central, ex: 1282
-- Date: 06/22/2004
--
-- Description:
-- This function divides the first argument by the second argument after
-- checking for NULL or 0 divisors to avoid "divide by zero" errors.
-- Change History:
--
-- Date Init. Description
-- 05/14/2009 RS Updated to handle really freaking big numbers, just in
-- case. :-)
-- 05/14/2009 RS Updated to handle negative divisors.
-- **************************************************************************
declare @p_product decimal(38,19);
select @p_product = null;
if ( @divisor is not null and @divisor <> 0 and @Numerator is not null )
select @p_product = @Numerator / @divisor;
return(@p_product)
end
go
Run Code Online (Sandbox Code Playgroud)