Во-первых, я бы перестроил ваш сценарий, чтобы мне не нужно было повторять сложные выражения (точнее, подвыборы) более одного раза.
Если возможно, используйте 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,
...
Может ли это помочь вам упростить запрос?