Получение предупреждения: значение Null исключается с помощью агрегатной или другой операции SET

У меня есть эта схема

create table t(id int, d date) 

insert into t (id, d) values (1, getdate()), 
                             (2, NULL)

При выполнении

declare @mindate date    
select @mindate = min(d) from t

Я получаю предупреждение

Значение Null исключается агрегированием или другой операцией SET

Почему и что я могу сделать с этим?

Ответ 1

Вы также можете ничего не делать.

Это просто информационное сообщение которое требуется в стандарте SQL. Он не имеет вредных последствий.

Причиной для возврата этого сообщения является то, что во время большинства операций в нулях SQL распространяются.

SELECT NULL + 3 + 7 возвращает NULL (относительно NULL как неизвестная величина, это имеет смысл, поскольку ? + 3 + 7 также неизвестен)

но

SELECT SUM(N)
FROM   (VALUES (NULL),
               (3),
               (7)) V(N) 

Возвращает 10 и предупреждение о том, что пустые значения игнорируются.

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

Какой самый тяжелый торт ниже? (Источник изображения, Creative Commons изображение изменено (обрезано и аннотировано) мной)

введите описание изображения здесь

После того, как третий торт был взвешен, чешуйки сломались, и поэтому нет информации о четвертом, но все же можно было измерить окружность.

+--------+--------+---------------+
| CakeId | Weight | Circumference |
+--------+--------+---------------+
|      1 | 50     | 12.0          |
|      2 | 80     | 14.2          |
|      3 | 70     | 13.7          |
|      4 | NULL   | 13.4          |
+--------+--------+---------------+

Запрос

SELECT MAX(Weight)        AS MaxWeight,
       AVG(Circumference) AS AvgCircumference
FROM   Cakes 

Возвращает

+-----------+------------------+
| MaxWeight | AvgCircumference |
+-----------+------------------+
|        80 |          13.325  |
+-----------+------------------+

хотя технически невозможно сказать с уверенностью, что 80 был весом самого тяжелого пирога (поскольку неизвестное число может быть больше), приведенные выше результаты обычно более полезны, чем просто возвращение неизвестных.

+-----------+------------------+
| MaxWeight | AvgCircumference |
+-----------+------------------+
|         ? |          13.325  |
+-----------+------------------+

Вероятно, вы хотите игнорировать NULL, и предупреждение просто предупреждает вас о том, что это происходит.

Ответ 2

Я думаю, что вы можете игнорировать это предупреждение в случае, поскольку вы используете функцию MIN.

"За исключением COUNT, агрегированные функции игнорируют нулевые значения

Пожалуйста, обратитесь Агрегатные функции (Transact-SQL)

Ответ 3

@juergen предоставил два хороших ответа:

  • Подавить предупреждение с помощью SET ANSI_WARNINGS OFF
  • Предполагая, что вы хотите включить значения NULL и относиться к ним как (скажем), используйте select @mindate = min(isnull(d, cast(0 as datetime))) from t

Однако, если вы хотите игнорировать строки, в которых столбец d имеет значение null и не относится к опции ANSI_WARNINGS, тогда вы можете сделать это, исключив все строки, где d установлено равным null:

select @mindate = min(d) from t where (d IS NOT NULL)

Ответ 4

Что должно min() вернуть в вашем случае как самое низкое значение d?

Ошибка сообщает вам, что функция min() не учитывала записи, которые являются null.

Поэтому, если он должен игнорировать значения null и вернуть самую низкую существующую дату, вы можете игнорировать это предупреждение.

Если вы также хотите подавить предупреждения для этого одного оператора, вы можете сделать это следующим образом:

set ansi_warnings off
select @mindate = min(d) from t
set ansi_warnings on

Если вы хотите, чтобы значения null учитывались с использованием значения по умолчанию для них, вы можете установить значение даты по умолчанию, подобное этому

select @mindate = min(isnull(d, cast(0 as datetime)))
from t

Ответ 5

Если вы хотите, чтобы агрегаты учитывали значения null и обрабатывали результат как null, вы можете использовать:

SELECT IIF(COUNT(N) != COUNT(*), NULL, SUM(N)) as [Sum]
FROM   (VALUES (NULL),
               (3),
               (7)) V(N) 

Это возвращает null, если не все значения.