Да, похоже, NULL
входные данные игнорируются этими агрегатами.
Этот тип глупости почти наверняка исходит из стандарта SQL (хотя я не собираюсь платить ) $ 200 , чтобы узнать наверняка). Другие стандартные агрегаты, такие как sum(var)
, работают таким образом, и кажется, что они, вероятно, просто экстраполируются оттуда, не принимая во внимание разницу между арифметическими c и логическими операциями, когда дело доходит до обработки null
значений.
Я не думаю, что есть способ обойти это; Я полагаю, что единственный способ убедить эти функции вернуть NULL
- передать им пустой набор данных. (Кроме того, тот, кто настаивал на том, что sum()
из нулевых строк должен быть NULL
, а не 0
, должен быть зафиксирован ...)
К счастью, Postgres бесконечно расширяем и определяет Ваши агрегаты довольно тривиальны:
CREATE FUNCTION boolean_and(boolean, boolean) RETURNS boolean AS
'SELECT $1 AND $2'
LANGUAGE SQL IMMUTABLE;
CREATE AGGREGATE sensible_bool_and(boolean)
(
STYPE = boolean,
INITCOND = true,
SFUNC = boolean_and,
-- Optionally, to allow parallelisation:
COMBINEFUNC = boolean_and,
PARALLEL = SAFE
);
Если вам просто нужно это для одноразового запроса, и вы не хотите (или не имеете разрешения) добавить новое определение агрегата в базу данных, вы можете поместить их в временную схему локального соединения, определив и сославшись на них как pg_temp.boolean_and()
/ pg_temp.sensible_bool_and()
.
(Если вы используете пул соединений, вы можете удалить их, когда вы готово.)
Обратите внимание, что это примерно в 10 раз медленнее, чем встроенный bool_and()
(хотя вряд ли это будет узким местом во многих реальных c случаях использования); SQL boolean
значения распределяются в куче и являются неизменяемыми, поэтому boolean_and()
необходимо выделять новое значение для каждой итерации, тогда как LANGUAGE C
функциям разрешено обновлять накопитель на месте. Если производительность вызывает беспокойство, и вы готовы / можете собрать и развернуть свой собственный модуль C, то (как и в случае большинства внутренних функций) вы можете довольно легко скопировать и вставить bool_and()
реализация и настроить его в соответствии с вашими потребностями.
Но все это отчасти излишне, если у вас нет реальной необходимости в этом. На практике я бы, вероятно, вместо решения @ Люка go.