Как решить исключение деления на ноль в хранимой процедуре SQL? - PullRequest
0 голосов
/ 02 февраля 2011

Когда я выполняю свою хранимую процедуру, она выдает Исключение деления на ноль. В моей базе данных нет данных за несколько месяцев. Как я могу решить это?

Ниже мой запрос.

@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 is rownumber.descrn также является номером строки в порядке убывания.

Как мне изменить мой запрос?

Пожалуйста, ответьте.

С уважением,

NSJ

Ответы [ 3 ]

2 голосов
/ 02 февраля 2011

Во-первых, я бы перестроил ваш сценарий, чтобы мне не нужно было повторять сложные выражения (точнее, подвыборы) более одного раза.

Если возможно, используйте 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 голос
/ 02 февраля 2011

Это ваше выражение очень неясное и трудное для понимания, и вы выбираете одно и то же значение несколько раз, что совершенно не нужно - поэтому я бы порекомендовал:

  • попробуйте сначала определить все биты и кусочки, которые могут быть использованы в ваших вычислениях - поместите результаты этих select top 1 .... запросов в переменные

  • затем проверьте перед тем, как делить на ноль, и если ваш делитель будет равен нулю, вам нужно подумать о другом решении / другом значении, которое следует использовать вместо ...

Ваша проблема заключается в следующем: вы в настоящее время проверяете, что ваше единственное значение равно < 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
0 голосов
/ 02 февраля 2011

Может быть, вам нужно '<= 0', а не '<0' в предложении if? Вы также, вероятно, должны убедиться, что в вашей временной таблице есть данные, которые соответствуют критериям rn = 1, в противном случае выборка вернет ноль. Если все остальное терпит неудачу, Sql2005 имеет блоки try try, так что вы можете перехватить деление на ноль исключения. </p>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...