Если подзапрос для сравнения через ALL не вернул строк, каким будет результат предиката и почему?
Результат будет TRUE. Предикат с ALL требует, чтобы сравнение было истинным для каждой строки подзапроса; если строк нет, нарушающего сравнение значения не существует. Это частный случай вакуу́мной истинности.
Кванторы «для всех» и «существует» происходят из реляционного исчисления. SQL предоставляет их через конструкции ALL и ANY/SOME, чтобы выражать сравнения с множеством значений без ручного перебора строк.
Такой подход отделяет условие от способа получения данных: подзапрос формирует набор значений, а внешний предикат определяет, должно ли сравнение быть истинным для всех или хотя бы для одного элемента.
Ошибка возникает, когда пустой результат подзапроса интуитивно принимают за «условие не выполнено». Для ALL это неверно: отсутствие строк не даёт контрпримера, поэтому условие «значение удовлетворяет сравнению со всеми строками» считается истинным.
Это влияет на фильтрацию, проверку порогов и бизнес-правила. Неправильная замена ALL на агрегатную функцию или на другую форму предиката может изменить результат именно для пустого набора.
Для предиката вида «значение сравнивается с ALL» действуют такие правила:
WHERE не проходит фильтрацию.Например, в следующем запросе внутренний подзапрос не возвращает строк, поэтому внешний предикат истинен:
Если бы подзапрос вернул значения 10 и 20, выражение 7 > ALL (...) стало бы FALSE. Если бы среди результатов был NULL, а явного ложного сравнения не было, результатом могло бы стать UNKNOWN.
Смысл ALL отличается от ANY. ALL соответствует универсальному условию «для каждого значения», а ANY — существовательному условию «существует хотя бы одно значение». Поэтому для пустого набора ALL возвращает TRUE, а ANY — FALSE.
Практическое следствие: при проектировании запроса нужно заранее определить, что означает отсутствие строк. Иногда пустой набор действительно означает отсутствие нарушений и должен давать TRUE; иногда требуется явно исключить этот случай дополнительной проверкой существования строк.
Система проверяет, что установленная цена товара выше всех исторических цен конкурентов. Если по товару ещё нет наблюдений, условие с ALL будет истинным.
Возможны три подхода:
Если отсутствие наблюдений означает «проверку выполнить нельзя», выбранным решением должна быть комбинация EXISTS и сравнения через ALL. Если же отсутствие наблюдений означает отсутствие ограничений, достаточно ALL. Такое решение явно фиксирует бизнес-смысл пустого набора и предотвращает неявную зависимость от поведения агрегатов.
Как изменится результат, если вместо ALL использовать ANY на пустом наборе?
Результат будет FALSE. ANY требует существования хотя бы одного значения, для которого сравнение истинно. В пустом наборе такого значения нет, поэтому существовательное условие не выполняется.
Что произойдёт, если подзапрос для ALL вернёт NULL и не вернёт ни одного значения, нарушающего сравнение?
Результатом станет UNKNOWN, а не TRUE. Сравнение с NULL само по себе неизвестно; если среди сравнений нет FALSE, но есть UNKNOWN, итоговый результат квантифицированного предиката также UNKNOWN. В WHERE такая строка будет исключена.
Можно ли всегда заменить сравнение через ALL на сравнение с MAX или MIN?
Нет, не всегда. При ненулевом наборе без NULL замена обычно эквивалентна для соответствующего монотонного оператора: например, сравнение с ALL можно связать с максимумом для оператора > или с минимумом для оператора <. Но на пустом наборе агрегат MAX или MIN возвращает NULL, что даёт UNKNOWN, тогда как ALL возвращает TRUE. Кроме того, NULL в исходных данных и необходимость различать пустой набор требуют отдельной обработки.