Sql server 2005 SQL Server:如何在查询中处理被0除的情况

Sql server 2005 SQL Server:如何在查询中处理被0除的情况,sql-server-2005,aggregate-functions,divide-by-zero,Sql Server 2005,Aggregate Functions,Divide By Zero,我有一个类似这样的查询,它得到一个百分比: SELECT SUM(convert(decimal(3,2), CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END))/ SUM(convert(decimal(3,2),CASE WHEN State_ID = 14 THEN 1 ELSE 0 END)) * 100 FROM SomeTable 在正常情况下,这可能返回类似于59.778

我有一个类似这样的查询,它得到一个百分比:

SELECT SUM(convert(decimal(3,2),
          CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END))/
          SUM(convert(decimal(3,2),CASE WHEN State_ID = 14 THEN 1 ELSE 0 END)) * 100
FROM SomeTable
在正常情况下,这可能返回类似于59.77803的值。但事实证明,在某些情况下,第二个和(分母)可能是0。有人知道如何解释这种情况并避免被0除的异常吗


我正在使用SQLServer2005。谢谢。

问问自己,当分母为0时,想要返回什么结果?
SELECT SUM(convert(decimal(3,2),
          CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END))/
          SUM(convert(decimal(3,2),CASE WHEN State_ID = 14 THEN 1 ELSE 0 END)) + 0.00000000001 * 100
FROM SomeTable
然后,基于此,相应地修复查询


没有好的内在方法来做这件事。这是一个业务逻辑问题。

问问自己,当分母为0时,您希望返回的结果是什么?
然后,基于此,相应地修复查询


没有好的内在方法来做这件事。这是一个业务逻辑问题。

如果我读对了,这应该是可行的:

SELECT SUM(convert(decimal(3,2), 
          CASE WHEN Status_ID = 1 THEN 1 ELSE 0 END))/ 
          SUM(convert(decimal(3,2),1)) * 100 
FROM SomeTable 
WHERE State_ID = 14 

如果我读对了,这应该可以:

SELECT SUM(convert(decimal(3,2), 
          CASE WHEN Status_ID = 1 THEN 1 ELSE 0 END))/ 
          SUM(convert(decimal(3,2),1)) * 100 
FROM SomeTable 
WHERE State_ID = 14 

若要避免被0除异常,可以使用一个函数,该函数接受分子、分母和默认值,以在分母为0时传递。并调用该函数进行除法

CREATE FUNCTION [dbo].[fn_divide] 
(
    @numerator DECIMAL(3,2),@denominator DECIMAL(3,2),@default DECIMAL(3,2)
)  
RETURNS DECIMAL(3,2) 

AS  BEGIN

 DECLARE @result DECIMAL(3,2)

 IF @denominator = 0
 BEGIN
    set @result=@default
 END
ELSE
 BEGIN
    set @result=@numerator/@denominator
 END 

  return @result
END

若要避免被0除异常,可以使用一个函数,该函数接受分子、分母和默认值,以在分母为0时传递。并调用该函数进行除法

CREATE FUNCTION [dbo].[fn_divide] 
(
    @numerator DECIMAL(3,2),@denominator DECIMAL(3,2),@default DECIMAL(3,2)
)  
RETURNS DECIMAL(3,2) 

AS  BEGIN

 DECLARE @result DECIMAL(3,2)

 IF @denominator = 0
 BEGIN
    set @result=@default
 END
ELSE
 BEGIN
    set @result=@numerator/@denominator
 END 

  return @result
END

真正的问题是,当你试图除以零时,“答案”应该是什么?我会将其设置为
NULL
,因此请尝试以下操作:

DECLARE @x int

set @x=5
select 1.0/NULLIF(@x,0)

set @x=0
select 1.0/NULLIF(@x,0)
输出:

---------------------------------------
0.200000000000

(1 row(s) affected)


---------------------------------------
NULL

(1 row(s) affected)
您的代码是:

SELECT SUM(convert(decimal(3,2), CASE
                                     WHEN Status_ID = 1 AND State_ID = 14 THEN 1 
                                     ELSE 0 
                                 END
                  )
          ) 
        /
        SUM(convert(decimal(3,2),CASE
                                     WHEN State_ID = 14 THEN 1 
                                     ELSE NULL   --<<<<<<<<<<<<force null if div by zero
                                 END
                   )
           )
        * 100
FROM SomeTable
选择SUM(转换)(十进制(3,2),大小写
当状态_ID=1且状态_ID=14时,则为1
其他0
结束
)
) 
/
总和(换算为十进制(3,2),大小写
当状态_ID=14时,则为1

ELSE NULL--真正的问题是,当你试图除以0时,“答案”应该是什么?我会将其设为
NULL
,所以试试这样的方法:

DECLARE @x int

set @x=5
select 1.0/NULLIF(@x,0)

set @x=0
select 1.0/NULLIF(@x,0)
输出:

---------------------------------------
0.200000000000

(1 row(s) affected)


---------------------------------------
NULL

(1 row(s) affected)
您的代码是:

SELECT SUM(convert(decimal(3,2), CASE
                                     WHEN Status_ID = 1 AND State_ID = 14 THEN 1 
                                     ELSE 0 
                                 END
                  )
          ) 
        /
        SUM(convert(decimal(3,2),CASE
                                     WHEN State_ID = 14 THEN 1 
                                     ELSE NULL   --<<<<<<<<<<<<force null if div by zero
                                 END
                   )
           )
        * 100
FROM SomeTable
选择SUM(转换)(十进制(3,2),大小写
当状态_ID=1且状态_ID=14时,则为1
其他0
结束
)
) 
/
总和(换算为十进制(3,2),大小写
当状态_ID=14时,则为1

ELSE NULL--我可能会使用NULL来表示不可计算的,但这取决于您在问题域中的意图(扩展代码以显示发生了什么):

如果表中没有行,分母将为零,则结果将被转换为NULL,从而整个表达式最终为NULL

该代码也可以简化一点(可能是因为它已经是一个简化的玩具问题):

作为将多个不同内容组合到一个查询中的示例:

SELECT CASE WHEN State_ID = 14 THEN 'State_ID = 14'
            WHEN State_ID IN (1, 2, 3) THEN 'State_ID IN (1, 2, 3)'
            ELSE 'DEFAULT'
       END AS Category
       ,SUM(convert(decimal(3,2),
                   CASE WHEN Status_ID = 1 THEN 1 ELSE 0 END)
          )
       /
       convert(decimal(3,2), COUNT(*))
       * 100
FROM SomeTable
GROUP BY CASE WHEN State_ID = 14 THEN 'State_ID = 14'
            WHEN State_ID IN (1, 2, 3) THEN 'State_ID IN (1, 2, 3)'
            ELSE 'DEFAULT'
       END

我可能会使用NULL来表示不可计算,但这取决于您在问题域中的意图(代码扩展以显示发生了什么):

如果表中没有行,分母将为零,则结果将被转换为NULL,从而整个表达式最终为NULL

该代码也可以简化一点(可能是因为它已经是一个简化的玩具问题):

作为将多个不同内容组合到一个查询中的示例:

SELECT CASE WHEN State_ID = 14 THEN 'State_ID = 14'
            WHEN State_ID IN (1, 2, 3) THEN 'State_ID IN (1, 2, 3)'
            ELSE 'DEFAULT'
       END AS Category
       ,SUM(convert(decimal(3,2),
                   CASE WHEN Status_ID = 1 THEN 1 ELSE 0 END)
          )
       /
       convert(decimal(3,2), COUNT(*))
       * 100
FROM SomeTable
GROUP BY CASE WHEN State_ID = 14 THEN 'State_ID = 14'
            WHEN State_ID IN (1, 2, 3) THEN 'State_ID IN (1, 2, 3)'
            ELSE 'DEFAULT'
       END


当总和为0时,你想要什么答案?当总和为0时,你想要什么答案?我会继续说,这似乎有点不对劲。但这真的是最好的方法吗?我想可能是一个“如果”检查或什么。当然有点不对劲,有100万%的损失。或者,你应该提供一个除以0的结果继续说,这似乎有点骇人听闻。但这真的是最好的方法吗?我想可能是一个“如果”检查或什么的。当然有点骇人听闻,有100万%的损失。或者,你应该提供一个除以0+1的结果。对,如果StateID 14的分子是零,那么分母是零不要紧。不幸的是,这是一个简化的问题。事实上,我有许多这样的SELECT语句,都来自一个表,并且给出了第三个条件(在WHERE子句中)我在这里没有具体说明。所以在WHERE子句中给出State_ID会失去我需要的粒度。不过,谢谢你的回答。+1。对,如果StateID 14的分子为零,那么分母就无关紧要了。不幸的是,这是一个简化的问题。实际上,我有很多这样的SELECT语句,都是从一开始的表,并给出了我在此处未指定的第三个条件(在WHERE子句中)。因此,在WHERE子句中提供State_ID将失去我所需的粒度。不过,感谢您的回答。这将为大型结果集增加一点开销,将为大型结果集增加一点开销SUM()中不包括NULLS,所以我不认为这能解决问题。@Cade Roux,如果它们都为空,那么整个和就是空的,如果一些为空,那么这些就被消除了,这是OP想要的?@KM你是对的,在这种情况下,没有办法从和中得到0。一般来说,你可能需要用空的if(,0)来包装和如果仍然有办法获得0个sum,则从sum()中排除空值,所以我不认为这能解决问题。@Cade Roux,如果它们都为空,那么整个和就是空的,如果一些为空,那么这些就被消除了,这是OP想要的?@KM你是对的,在这种情况下,没有办法从和中得到0。一般来说,你可能需要用空的if(,0)来包装和如果还有一种方法可以得到0和。@如果你是对的,这是一个简化的问题。实际上,我有很多这样的SELECT语句,都来自一个表,并且给出了第三个条件,我在这里没有指定。所以在WHERE中给出State_ID