Za prvé, problém, který tu máte, je, že říkáte:"Pokud je známka nižší než 70, hodnota tohoto výrazu pro případ je count(rank). Jinak je hodnota tohoto výrazu count(rank) ." Takže v obou případech vždy dostanete stejnou hodnotu.
SELECT
CASE
WHEN grade < 70 THEN COUNT(rank)
ELSE COUNT(rank)
END
FROM
grades
count() počítá pouze hodnoty, které nejsou nulové, takže obvykle uvidíte tento vzor, abyste dosáhli toho, o co se pokoušíte:
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
Tímto způsobem se výraz případu vyhodnotí jako 1 pouze tehdy, když je testovací výraz pravdivý, a jinak bude mít hodnotu null. Potom count() bude počítat pouze nenulové instance, tj. když je testovací výraz pravdivý, což by vám mělo poskytnout to, co potřebujete.
Edit:Jako vedlejší poznámku si všimněte, že je to úplně stejné, jako jste to původně napsali pomocí count(if(test, true-value, false-value))
, pouze přepsáno jako count(case when test then true-value end)
(a null je stojan ve falešné hodnotě, protože else
nebylo dodáno k pouzdru).
Edit:postgres 9.4 byl vydán několik měsíců po této původní výměně. Tato verze zavedla agregované filtry, díky nimž mohou scénáře jako tento vypadat o něco hezčí a jasnější. Tato odpověď stále dostává občasné kladné hlasy, takže pokud jste narazili zde a používáte novější postgres (tj. 9.4+), možná budete chtít zvážit tuto ekvivalentní verzi:
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