如何在SQL存储过程中解决除零异常?

时间:2011-02-02 05:59:35

标签: sql-server-2005 tsql

当我执行我的存储过程时,它会抛出Divide By zero Exception。因为在我的数据库中,几个月没有数据。我该如何解决这个问题?

以下是我的询问。

@diffNSVY FLOAT = 0      --I have declared @diffNSVY as optional parameter.

SET @diffNSVY = CASE 
       WHEN (select top 1 NSV from #temp where rn = 1) < 0 THEN 0 
          ELSE (((select top 1 NSV from #temp where descrn = 1) - (select top 1 NSV from #temp where rn = 1))*1.0)/(select top 1 NSV from #temp where rn = 1)  
       END

我将结果集插入#temp表。 NSV是列名。 rn rownumber.descrn也是递减顺序的行号。

如何修改我的查询?

请回复。

此致

NSJ

3 个答案:

答案 0 :(得分:2)

首先,我会重建你的脚本,所以我不需要多次重复复杂的表达式(确切地说是子选择)。

如果可能,请使用SELECT而不是SET,如下所示:

SELECT @diffNSVY = CASE
   WHEN rn.NSV < 0 THEN 0
   ELSE (descrn.NSV - rn.NSV) * 1.0 / rn.NSV  /* extra '()' are removed as unneeded */
FROM
  (select top 1 NSV from #temp where rn = 1) AS rn,
  (select top 1 NSV from #temp where descrn = 1) AS descrn

接下来,问问自己,如果被零除,结果应该是什么。它应该也是零吗?然后下一个优化步骤就是:

SELECT @diffNSVY = CASE
   WHEN rn.NSV <= 0 THEN 0  /* changed '<' to '<=' to account for division by zero */
   ELSE (descrn.NSV - rn.NSV) * 1.0 / rn.NSV
FROM
  (select top 1 NSV from #temp where rn = 1) AS rn,
  (select top 1 NSV from #temp where descrn = 1) AS descrn

但是如果您希望结果变为未定义(NULL)以便稍后处理,那么您可以通过以下方式实现:

SELECT @diffNSVY = CASE
   WHEN rn.NSV < 0 THEN 0
   ELSE (descrn.NSV - rn.NSV) * 1.0 / CASE rn.NSV WHEN 0 THEN NULL ELSE rn.NSV END
FROM
  (select top 1 NSV from #temp where rn = 1) AS rn,
  (select top 1 NSV from #temp where descrn = 1) AS descrn

一般来说,当我需要保护自己免于被零除错误时,我发现这种模式非常有用。我经常这样使用它:

...ISNULL(some_expression / CASE @Value WHEN 0 THEN NULL ELSE @Value END, 0)...

有时我在没有ISNULL的情况下使用它,在这种情况下,我稍后使用更复杂的逻辑处理可能的NULL结果。

编辑:哦,还有一件事:使用SELECT,您可以同时进行多项任务,如下所示:

SELECT
  @Var1 = expression1,
  @Var2 = expression2,
  ...

这可能会帮助您简化查询吗?

答案 1 :(得分:1)

你的表达非常清楚,难以理解,而且你选择相同的值几次是完全没必要的 - 所以我的推荐是:

  • 尝试首先确定可能进入您计算的所有部分 - 将select top 1 ....个查询的结果放入变量中

  • 然后检查,然后除以零,如果除数为零,则需要考虑使用另一个解决方案/另一个值...

    < / LI>

你的问题是这样的:你目前只检查你的一个值是< 0然后你的返回0 - 否则(包括那个值是= 0时)你返回一个表达式是一个正好用这个值除......你还需要添加一个特殊情况:如果那个值是= 0,你就不能使用你的表达式,因为这会导致除以零的异常 - 你需要返回一些其他的值在这种情况下!

所以你的代码应该是这样的:

DECLARE @diffNSVY FLOAT = 0      --I have declared @diffNSVY as optional parameter.

DECLARE @RNValue INT
SET @RNValue = (SELECT TOP 1 NSV FROM #temp WHERE rn = 1) 

DECLARE @DescRNValue INT
SET @DescRNValue = (SELECT TOP 1 NSV FROM #temp WHERE descrn = 1)


SET @diffNSVY = 
   CASE 
      WHEN @RNValue < 0 THEN 0 
      WHEN @RNValue = 0 THEN ....... <-- you need to define a value here! CAnnot divide by @RNValue if it's ZERO !
      ELSE ((@DescRNValue - @RNValue)  * 1.0) / @RNValue
   END

答案 2 :(得分:0)

也许你的if子句需要'&lt; = 0'而不是'&lt; 0'?您还应该确保临时表中的数据符合rn = 1条件,否则选择将返回null。如果所有其他方法都失败了,Sql2005会尝试使用catch块,因此您可以捕获除以零的异常。