#sql #postgresql #presto
#sql #postgresql #presto
Вопрос:
У меня есть запрос ниже в виде:
SELECT
d.name,
SUM(CASE WHEN e.salary > 100000 THEN 1 ELSE 0 END)
/ COUNT(DISTINCT e.id)
AS pct_above_100k,
COUNT(DISTINCT e.id) AS c
FROM employees e JOIN departments d ON e.department_id = d.id
GROUP BY 1
HAVING COUNT(*) > 10
ORDER BY 2 DESC
Я использую здесь sum, но была бы какая-либо разница, если бы я использовал count?
Я знаю, что count подсчитывает количество раз, когда значение существует, а sum суммирует фактические значения, но здесь, поскольку мое условие таково, что если зарплата > 100000, это все равно будет выглядеть как 1, верно?
Спасибо!
Комментарии:
1. Правильно.
Count
получил бы тот же результат.2. Я не согласен, Count все равно будет считать строку, независимо от того, равно ли ее значение 0 или 1, в то время как sum будет суммироваться, т. е. если значение условия if выполняется три раза, то оно вернет 3, в то время как count вернет количество строк, независимо от того, является условие true или false.
3.
sum
Это то же самое, чтоcount(*) filter (where e.salary > 10000) ....
Ответ №1:
Мы считаем условно с предложением filter:
COUNT(*) FILTER (WHERE e.salary > 100000)
Некоторые другие СУБД не поддерживают предложение filter. Здесь мы используем обходные пути, самостоятельно вычисляя выражение с помощью CASE WHEN
и либо используем COUNT
or SUM
для суммирования совпадений. Вот несколько способов сделать это:
SUM(CASE WHEN e.salary > 100000 THEN 1 ELSE 0 END)
COUNT(CASE WHEN e.salary > 100000 THEN 1 ELSE NULL END)
COUNT(CASE WHEN e.salary > 100000 THEN 1 END)
COUNT(CASE WHEN e.salary > 100000 THEN 'count this' END)
Поскольку PostgreSQL поддерживает предложение filter, вы должны использовать COUNT(*) FILTER (...)
.
Ответ №2:
Если бы вы просто заменили sum
на count
, вы бы получили другой результат, поскольку 0 считается столько же, сколько 1.
Самый элегантный способ написать это — FILTER
предложение, как упоминали другие, но вы также могли бы сделать это:
count(CASE WHEN e.salary > 100000 THEN 0 END)
Это сработало бы, потому что значения NULL игнорируются (большинством) агрегатных функций.
Ответ №3:
Предположительно, сотрудники не находятся в нескольких отделах, поэтому count(distinct)
нет необходимости.
Это означает, что код может быть более просто записан как:
AVG(CASE WHEN e.salary > 100000 THEN 1 ELSE 0 END) AS pct_above_100k,
Или:
AVG( (e.salary > 100000)::int ) AS pct_above_100k,
Они будут более эффективными, чем альтернативы, потому что COUNT(DISTINCT)
обычно немного дороже, чем другие функции агрегирования.