openlang

COUNT(col) поменял смысл доли в отчёте

Отчёт показывал долю заказов с датой отправки как COUNT(shipped_at) * 1.0 / COUNT(*). Какое-то время это было верно. Потом в ту же таблицу начали попадать ожидающие заказы с shipped_at в NULL, и доля упала. В запросе не поменялось ничего.

COUNT(*) считает входные строки. COUNT(shipped_at) считает строки, где это значение не NULL. Доля всегда была «строки с датой среди всех строк», и под ней сдвинулось само множество строк.

Проверить нужно три вещи, и они не равноценны.

  1. Назвать знаменатель. COUNT(*) FILTER (WHERE status <> 'pending') говорит, о каких строках эта доля.
  2. Следить за делением. В PostgreSQL count возвращает bigint, поэтому COUNT(a) / COUNT(*) обрезает до нуля любую долю меньше единицы. Отсюда * 1.0.
  3. Спросить, что значит NULL в этом столбце. «Ещё не отправлен» и «дата отправки неизвестна» - разные факты, и подсчёт их не различит.

Хватит двух отправленных заказов и двух ожидающих, чтобы два варианта разошлись у всех на виду.

SELECT COUNT(shipped_at) * 1.0 / COUNT(*) AS naive,
       COUNT(shipped_at) * 1.0
         / COUNT(*) FILTER (WHERE status <> 'pending')
         AS shipped_share
FROM orders;
-- naive 0.5, shipped_share 1.0

В R есть такое же разделение. length(x) считает элементы NA, sum(!is.na(x)) их не считает. Когда отчёт собирается в R, я печатаю sum(is.na(x)) рядом с долей, чтобы читатель видел, сколько строк пропустил числитель.

Разговор продолжается 1

Следуя доводам
  1. Ссылка на ответ

    Выводите COUNT(*) - COUNT(shipped_at) рядом с долей. Тогда такой сдвиг приходит числом, а не загадкой.

Другие стороны того же вопроса

  1. count(*) пришёл строкой, и 12 + 1 дало 121

    Экран списка дел. В шапке 12 задач, я добавляю ещё одну и, чтобы поднять число до ответа сервера, делаю total + 1. В шапке те…

    Ответы 7typescriptsql
  2. rows.Next вернул false, а ошибка потерялась

    Маленькая утилита на database/sql вернула половину списка. Без ошибки. Код такой. Контекст с дедлайном. Дедлайн истёк посреди…

    Ответы 3sqlgo
  3. UPDATE перепроверяет WHERE после ожидания

    Две сессии под PostgreSQL Read Committed, один счёт с балансом 15, и обе сессии выполняют один и тот же оператор. Сессия A об…

    Ответы 0sql