Возвращает счетчики для нескольких диапазонов в одном операторе SELECT

9

У меня есть таблица базы данных Postgres, в fooкоторой, помимо прочего, есть столбец для scoreзначений от 0 до 10. Я хочу, чтобы запрос возвращал общее количество баллов, количество баллов от 0 до 3, количество баллов от 4 и 6, и количество баллов от 7 до 10. Что-то вроде следующего:

SELECT
  COUNT(*) as total,
  COUNT(
    SELECT * from foo where score between 0 and 3;
  ) as low,
  COUNT(
    SELECT * from foo where score between 4 and 6;
  ) as mid,
  COUNT(
    SELECT * from foo where score between 7 and 10;
  ) as high
FROM foo;

Я попробовал это, но получил ошибку SELECTв COUNTзаявлениях. Есть идеи, как я могу это сделать? Я уверен, что в Postgres есть супер простой способ. Я просто не могу найти правильные условия для Google.

Bryan
источник

Ответы:

7

Просто используйте условные SUM()операторы на столбец для каждого диапазона чисел. Итог может быть суммирован, просто используя SUM(1), предполагая, что все данные в таблице находятся в пределах одного из диапазонов - если нет, просто ограничьте это как с другими.

select sum(case when score between 0 and 3 then 1 else 0 end) as minrange,
       sum(case when score between 4 and 6 then 1 else 0 end) as midrange,
       sum(case when score between 7 and 10 then 1 else 0 end) as maxrange,
       sum(1) as total
from foo;

Ссылка SQL Fiddle .

Philᵀᴹ
источник
8

Совокупное FILTERпредложение в Postgres 9.4+

Начиная с Postgres 9.4, существует простой и быстрый (стандарт SQL) способ:

SELECT count(*) FILTER (WHERE score BETWEEN 0 AND 3)  AS low
     , count(*) FILTER (WHERE score BETWEEN 4 AND 7)  AS mid
     , count(*) FILTER (WHERE score BETWEEN 8 AND 10) AS high
     , count(*)                                       AS total
FROM   foo;

totalскладывается low, midи high, если не участвуют NULL или другие значения.

Ссылки:

Также читайте ниже.

Postgres 9,3-

Есть несколько методов:

@Phil предоставляет стандартный способ с CASEутверждением (за исключением того sum(1), что это не стандартный способ). Мне нравится использовать более короткую форму:

SELECT count(score BETWEEN 0 AND 3  OR NULL) AS low
     , count(score BETWEEN 4 AND 6  OR NULL) AS mid
     , count(score BETWEEN 7 AND 10 OR NULL) AS high
     , count(*)                              AS total
FROM   foo;

Если ваши значения соответствуют определенным в вашем вопросе (только 0- 10возможно), упростите далее:

SELECT count(score < 4 OR NULL)             AS low
     , count(score BETWEEN 4 AND 6 OR NULL) AS mid
     , count(score > 6 OR NULL)             AS high
     , count(*)                             AS total
FROM   foo;

Немного короче, чуть быстрее.

Тонкие различия

Есть тонкие различия , когда по сравнению с sum()в ответ Фила :

  • Самое главное, согласно документации :

    Следует отметить, что за исключением countэтих функций, возвращается нулевое значение, когда строки не выбраны. В частности, sumни одна строка не возвращает ноль, а не ноль, как можно было бы ожидать, ...

  • count(*) это стандартный способ и немного быстрее, чем sum(1). Снова, ноль против 0 применяется.

Любой из этих запросов (включая Фил) считает нулевые значения для total. Если это не желательно, используйте вместо этого:

count(score) AS total_not_null

SQL Fiddle в pg 9.3.
дБ <> скрипка здесь в стр. 10.

Эрвин Брандштеттер
источник