Primeiro, o problema que você está tendo aqui é que o que você está dizendo é "Se a nota for menor que 70, o valor desta expressão case é count(rank). Caso contrário, o valor desta expressão é count(rank) ." Então, em ambos os casos, você está sempre obtendo o mesmo valor.
SELECT
CASE
WHEN grade < 70 THEN COUNT(rank)
ELSE COUNT(rank)
END
FROM
grades
count() conta apenas valores não nulos, então normalmente o padrão que você verá para realizar o que está tentando é este:
SELECT
count(CASE WHEN grade < 70 THEN 1 END) as grade_less_than_70,
count(CASE WHEN grade >= 70 and grade < 80 THEN 1 END) as grade_between_70_and_80
FROM
grades
Dessa forma, a expressão case só será avaliada como 1 quando a expressão de teste for verdadeira e será nula caso contrário. Então o count() contará apenas as instâncias não nulas, ou seja, quando a expressão de teste for verdadeira, o que deve fornecer o que você precisa.
Edit:Como uma observação lateral, observe que isso é exatamente o mesmo que você escreveu originalmente usando
count(if(test, true-value, false-value))
, apenas reescrito como count(case when test then true-value end)
(e null é o stand em false-value já que um else
não foi fornecido ao caso). Edit:o postgres 9.4 foi lançado alguns meses após essa troca original. Essa versão introduziu filtros agregados, que podem tornar cenários como esse um pouco mais bonitos e claros. Esta resposta ainda recebe alguns upvotes ocasionais, então se você se deparou aqui e está usando um postgres mais recente (ou seja, 9.4+), você pode querer considerar esta versão equivalente:
SELECT
count(*) filter (where grade < 70) as grade_less_than_70,
count(*) filter (where grade >= 70 and grade < 80) as grade_between_70_and_80
FROM
grades