Почему count(*) возвращает несколько результатов в этом подзапросе (postgresql)?

Я хочу сгруппировать результаты запроса count(*) в сегменты значений. Я тестирую это на примере базы данных dellstore2 postgresql. Мой запрос ниже возвращает правильные ответы, но делает это один раз для каждой строки в таблице (несколько тысяч одинаковых результатов). Я могу исправить это, добавив LIMIT 1 в конец запроса, но я хотел бы понять, почему я получаю дубликаты, если это указывает на более широкую проблему с моим подходом. Запрос:

SELECT
    (SELECT count(*)
        FROM
            orders
        WHERE
            totalamount > 0 AND totalamount <= 100) AS ">0 <= 100",
    (SELECT count(*)
        FROM
            orders
        WHERE
            totalamount > 100 AND totalamount <= 200) AS ">100 <= 200"
...
FROM
    orders;

РЕДАКТИРОВАТЬ Ответ Андомара также позволил мне найти следующий подход (адаптированный из примера в SQL в двух словах (О'Рейли)). Это позволяет мне иметь сегменты в одном столбце со строкой для каждой пары сегмент/ответ. Я подумал, что включу его для всех, у кого есть такой вариант использования:

SELECT CASE
        WHEN totalamount IS NULL THEN 'Unknown'
        WHEN totalamount <= 100 THEN 'Not more than 100'
        WHEN totalamount <= 200 THEN 'Not more than 200'
        ELSE 'Over 200'
    END "Bucket",
    COUNT(*) "Number of results"
FROM
    orders
GROUP BY CASE
        WHEN totalamount IS NULL THEN 'Unknown'
        WHEN totalamount <= 100 THEN 'Not more than 100'
        WHEN totalamount <= 200 THEN 'Not more than 200'
        ELSE 'Over 200'
    END
ORDER BY
    MIN(totalamount);

person cms_mgr    schedule 20.03.2012    source источник
comment
Кажется, не хватает нескольких закрывающих скобок. Пожалуйста, опубликуйте реальный код.   -  person wildplasser    schedule 20.03.2012
comment
Спасибо wildplasser — теперь исправлено (я работаю на двух неподключенных машинах, поэтому не могу вырезать и вставлять).   -  person cms_mgr    schedule 20.03.2012


Ответы (2)


Вы выбираете каждую строку из orders, а затем для каждой строки оцениваются подзапросы.

Вместо этого рассмотрите этот подход:

select  count(case when 0 < totalamount and totalamount <= 100 then 1 end)
            as "<0,100]"
,       count(case when 100 < totalamount and totalamount <= 200 then 1 end)
            as "<100,200]"
from    Orders

Это позволит вычислить оба агрегата за одно сканирование таблицы.

person Andomar    schedule 20.03.2012
comment
Спасибо Андомар, это прекрасно. - person cms_mgr; 20.03.2012

Потому что вы включили их как подзапрос. Судя по всему, оба подзапроса count выполняются для каждой строки в таблице orders. Если вы опустите часть from из основного запроса, вы должны получить только одну строку.

Например, запрос

SELECT 'John Doe' FROM orders

возвращает «Джон Доу» для каждой строки в таблице заказов.

SELECT 'John Doe'

выбирает только одну строку.

Отказ от ответственности: это поведение сервера sql.

person Jesse van Assen    schedule 20.03.2012
comment
Спасибо, Джесси, это сработало, но я отметил решение Андомара выше, потому что я чувствовал, что его подход к запросу был более читабельным, чем мой оригинал. - person cms_mgr; 20.03.2012