sql >> Databasteknik >  >> RDS >> PostgreSQL

I Redshift/Postgres, hur räknar man rader som uppfyller ett villkor?

För det första, problemet du har här är att det du säger är "Om betyget är mindre än 70 är värdet på detta kasusuttryck count(rank). Annars är värdet på detta uttryck count(rank) ." Så i båda fallen får du alltid samma värde.

SELECT 
    CASE
        WHEN grade < 70 THEN COUNT(rank)
        ELSE COUNT(rank)
    END
FROM
   grades

count() räknar bara icke-nullvärden, så vanligtvis är mönstret du ser för att uppnå det du försöker:

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

På så sätt kommer kasusuttrycket bara att utvärderas till 1 när testuttrycket är sant och kommer att vara null annars. Då kommer count() bara att räkna de icke-null-instanser, d.v.s. när testuttrycket är sant, vilket borde ge dig det du behöver.

Edit:Som en sidoanteckning, lägg märke till att detta är exakt samma som hur du ursprungligen skrev detta med count(if(test, true-value, false-value)) , endast omskriven som count(case when test then true-value end) (och null är ställningen i falskt värde sedan en else inte levererades till fallet).

Edit:postgres 9.4 släpptes några månader efter detta ursprungliga utbyte. Den versionen introducerade aggregerade filter, som kan få scenarier som detta att se lite snyggare och tydligare ut. Det här svaret får fortfarande enstaka uppröstningar, så om du har snubblat på här och använder en nyare postgres (dvs. 9.4+) kanske du vill överväga denna motsvarande version:

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


  1. Performance Issues:The First Encounter

  2. Generera dynamiskt kolumner i PostgreSQL

  3. Hur man bygger en Access-databas i molnet

  4. Kopiera PostgreSQL-databas till en annan server