Условия в агрегатных функциях

Я решал некоторые задачи SQL и запутался в следующем:

CREATE TABLE data (
  len INT
);

INSERT INTO data (len)
VALUES 
  (NULL),
  (100), 
  (200),
  (300),
  (400);

предположим, мы создали такую ​​таблицу и хотим посчитать все значения меньше 200. Для этого я использую этот онлайн-компилятор.

моя первая попытка дает 1, как и ожидалось

SELECT COUNT(*) FILTER (WHERE len < 200)
FROM data

потом я подумал, могу ли я упростить это и просто сделать

SELECT COUNT(len < 200) FROM data

но он дает 4 в качестве ответа.

Итак, мой вопрос: можем ли мы использовать логические выражения внутри агрегатных функций? Если ответ НЕТ, то почему?

Привет! Почему бы вам просто не использовать «SELECT COUNT(*) FROM data WHERE len <200»? Кажется, вы слишком усложняете то, что должно быть очень простым запросом.

NickW 03.08.2024 17:59

Попробуйте SELECT COUNT(case when len < 200 then 1 else null end) FROM data Выход — 1. Count(value) — подсчитывает не нулевые значения. Значение (len<200) имеет значение true или false, а не null.

ValNik 03.08.2024 18:06

@ValNik, это выглядит неаккуратно, я думаю, нам следует избегать конструкций if-else, насколько это возможно =). Собственно вопрос возник потому что я попробовал написать ваш код как SELECT count(len < 200) и он не работает и я просто пытаюсь понять почему (что происходит с SELECT COUNT(len < 200)

myfakeaccount 03.08.2024 18:21

@NickW, да, ты прав. Я просто пытаюсь понять ошибку, с которой столкнулся. Если бы это было рабочее задание, я бы просто написал WHERE, как вы предлагали.

myfakeaccount 03.08.2024 18:22

Функция COUNT будет подсчитывать ненулевые записи. Ваше условие len < 200 возвращает ненулевые логические результаты почти для каждой записи в данных. то есть. Значения TRUE и FALSE участвуют в подсчете результатов. Единственная запись, которая не учитывается, — это значение NULL в таблице, поскольку NULL < 200 возвращает NULL.

Hitobat 03.08.2024 19:25

Вы можете использовать логическое выражение в агрегатной функции. Вы должны знать, как работает агрегатная функция. Я о функции count(). И выражение (len<200) имеет значение true или false, а не null. Count() считает ненулевые значения. И вы можете избежать конструкции if-else, если хотите;)

ValNik 03.08.2024 20:16

@ValNik, ELSE NULL в выражении CASE избыточно. Добиться желаемого результата можно и с помощью COUNT(NULLIF(len < 200, FALSE)). Выбор между функционально эквивалентным кодом должен определяться читабельностью; т. е. какая конструкция наиболее четко передает намерение и минимизирует когнитивную нагрузку.

JohnH 03.08.2024 20:23

См. пример без if-else SELECT sum(cast(len<200 as int)) FROM data Или SELECT sum((len<200)::int) FROM data

ValNik 03.08.2024 20:23

@JohnH, да, вы правы, ELSE null избыточен (по умолчанию). Я хотел выделить именно count(null).

ValNik 03.08.2024 20:34
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
9
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

COUNT(expression) вычисляет количество строк, для которых expression не является NULL. COUNT(*) вычисляет общее количество строк, поскольку * — это значение строки, которое никогда не бывает NULL ни для одной строки, даже если каждый столбец в строке имеет значение NULL. Оператор < может вернуть один из трех результатов: TRUE, FALSE или NULL. Имейте в виду, что NULL — это не значение, это состояние. Выражение COUNT(len < 200) возвращает NULL только тогда, когда len равно NULL; следовательно, любое значение len будет способствовать подсчету. COUNT(NULL) всегда будет возвращать 0 независимо от количества строк.

count(*) подсчитывает все входные строки независимо от их содержимого. Период. Это соответствует стандарту SQL и не зависит от значения символа * в других контекстах.

В Postgres есть отдельная (более быстрая) реализация для count(*). Инструкция:

count ( * ) → bigint

Вычисляет количество входных строк.

count ( "any" ) → bigint

Вычисляет количество входных строк, в которых входное значение не является нулевой.

Определение варианта count("any") также отвечает на вопрос, почему ваш второй запрос считает все строки с ненулевым значением len.

Чтобы на самом деле упростить ваш запрос и сделать его быстрее или значительно быстрее для больших таблиц и выборочных критериев, соответствующих индексу:

SELECT count(*) FROM data WHERE len < 200;

Видеть:

Другие вопросы по теме