#sql #sql_server
Есть временная таблица следующего вида:
CREATE TABLE #1 (
num1 FLOAT
,num2 FLOAT
)
INSERT INTO #1
SELECT 0
,0
INSERT INTO #1
SELECT 0
,1
INSERT INTO #1
SELECT 1
,0
INSERT INTO #1
SELECT 1
,1
Выполняю следующий запрос и он валится с ошибкой:
SELECT *
FROM #1 a
WHERE (
a.num1 > 0
AND a.num2 = 0
)
OR (
a.num1 > 0
AND a.num2 > 0
AND a.num1 / a.num2 >= 2
)
OR (
a.num1 >= 0
AND a.num2 < 0
)
Divide by zero error encountered.
Покурил справку, там написано, что операция деления выполняется раньше всех логических
операций. Ок, теперь стало понятно, почему валится с ошибкой.
Но потом я убираю знак "=" из последнего условия и все работает:
SELECT *
FROM #1 a
WHERE (
a.num1 > 0
AND a.num2 = 0
)
OR (
a.num1 > 0
AND a.num2 > 0
AND a.num1 / a.num2 >= 2
)
OR (
a.num1 > 0
AND a.num2 < 0
)
Посмотрел план выполнения запроса:
Судя по плану выполнения запроса, должна была снова возникнуть ошибка деления на
ноль. Но этого не произошло. Проверял на Microsoft SQL Server-е версии 2005 и 2012.
Проблема такая везде присутствует. В Teradata первый запрос отрабатывает без проблем.
Мой вопрос не в том, как переписать запрос, чтобы все заработало, а ПОЧЕМУ оно так
работает. Почему, когда во втором запросе я убираю знак "=" запрос отрабатывает без
проблем?
Ответы
Ответ 1
По-видимому дело вот в чём. Посмотрите план выполнения (XML). Когда вы убираете =, то предикат оптимизируется в (отредактировано для краткости)т.е. a.num1 > 0 AND ( a.num2 = 0 OR a.num1 / a.num2 >= 2 AND a.num2 > 0 OR a.num2 < 0 ) Строки данных (0, 0) и (0, 1) отсекаются по условию a.num1 > 0. Строки (1, 0) и (1, 1) ему удовлетворяет, но (1, 0) проходит по условию a.num2 = 0 (до деления не доходит). Строка (1, 1) не проходит ни по одному условию OR. Для сравнения, в неизменённом запросе предикат (также отредактировано для краткости), взятый из оценочного плана запроса, выглядит так: num1 > 0 num2 = 0 num1 / num2 >= 2 AND num2 > 0 num2 < 0 num1 > 0 AND num2 = 0 num1/num2 >= 2 AND num1 > 0 AND num2 > 0 num1 >= 0 AND num2 < 0 Ответ 2
Из плана видно, что значения трактуются как вещественные. Вещественное деление на ноль приводит к результату NaN (не число). В то время как челочисленное деление на ноль приводит к ошибке Divide by zero. Вероятно, сравнение > трактуется как неточное сравнение с нулём, отсюда вещественные числа. А сравнение >= трактуется как точное сравнение, отсюда челые числа.
Комментариев нет:
Отправить комментарий