SQL Server-Äquivalent einer COUNTIF-Aggregatfunktion

164

Ich erstelle eine Abfrage mit einer GROUP BYKlausel, die die Fähigkeit benötigt, Datensätze nur basierend auf einer bestimmten Bedingung zu zählen (z. B. nur Datensätze zählen, bei denen ein bestimmter Spaltenwert gleich 1 ist).

SELECT  UID, 
        COUNT(UID) AS TotalRecords, 
        SUM(ContractDollars) AS ContractDollars,
        (COUNTIF(MyColumn, 1) / COUNT(UID) * 100) -- Get the average of all records that are 1
FROM    dbo.AD_CurrentView
GROUP BY UID
HAVING  SUM(ContractDollars) >= 500000

Die COUNTIF()Zeile schlägt offensichtlich fehl, da keine native SQL-Funktion aufgerufen COUNTIFwird. Hier geht es jedoch darum, den Prozentsatz aller Zeilen zu bestimmen, die den Wert '1' für MyColumn haben.

Überlegen Sie, wie Sie dies in einer MS SQL 2005-Umgebung ordnungsgemäß implementieren können?

senfo
quelle

Antworten:

339

Sie könnten ein SUM(nicht COUNT!) In Kombination mit einer CASEAussage wie folgt verwenden:

SELECT SUM(CASE WHEN myColumn=1 THEN 1 ELSE 0 END)
FROM AD_CurrentView

Hinweis: In meinen eigenen Tests waren NULLs kein Problem, obwohl dies umgebungsabhängig sein kann. Sie könnten mit Nullen umgehen wie:

SELECT SUM(CASE WHEN ISNULL(myColumn,0)=1 THEN 1 ELSE 0 END)
FROM AD_CurrentView
JoshBerke
quelle
3
(Ich weiß, dass das OP nach MS SQL gefragt hat, aber nur ein kleiner Kommentar für SQLite-Benutzer, die dasselbe tun.) SQLite hat keine ISNULL, stattdessen können Sie dies tun CASE WHEN myColumn IS NULLoder verwenden ifnull( stackoverflow.com/a/799406/1861346 )
Matt
54

Normalerweise mache ich das, was Josh empfohlen hat, aber ich habe mir eine etwas hokey Alternative ausgedacht, die ich gerne teilen wollte.

Sie können die Tatsache nutzen, dass COUNT (ColumnName) keine NULL-Werte zählt, und Folgendes verwenden:

SELECT COUNT(NULLIF(0, myColumn))
FROM AD_CurrentView

NULLIF - gibt NULL zurück, wenn die beiden übergebenen Werte identisch sind.

Vorteil: Drückt Ihre Absicht aus, Zeilen zu zählen, anstatt die SUM () - Notation zu haben. Nachteil: Nicht so klar, wie es funktioniert ("Magie" ist normalerweise schlecht).

Chris Shaffer
quelle
2
Diese Lösung kann andere Antworten geben als die Summe, wenn eine Gruppe nur Nullen enthält, die zu 1 statt 0 führen.
KimvdLinde
Alter Beitrag, aber danke das hat geholfen. Ich erweiterte die Magie und umging das Problem "nur Nullen", indem ich ISNULLFolgendes hinzufügte : SELECT COUNT(NULLIF(0, ISNULL(myColumn, 0))). Warten Sie, das sieht nur hässlich aus ...
pcdev
1
Wäre perfekt, wenn es eine NULLIFNOT-Funktion
gäbe
21

Ich würde diese Syntax verwenden. Es entspricht den Vorschlägen von Josh und Chris, ist jedoch ANSI-konform und nicht an einen bestimmten Datenbankanbieter gebunden.

select count(case when myColumn = 1 then 1 else null end)
from   AD_CurrentView
asgeo1
quelle
2
Chris 'Antwort ist Stndard SQL-konform (Hinweis: NULLIFist in Standard SQL-92 enthalten). Joshs Antwort lässt sich leicht in Standard - SQL umgewandelt werden durch Ersetzen isnullmit COALESCE.
Tag, wenn der
Diese Antwort gefällt mir eigentlich am besten, weil sie auf die Idee kommt, "Zeilen zu zählen", die Chris gezeigt hat, aber erweiterbarer ist, da Sie jeden Vergleichsoperator verwenden können. nicht nur =. Ich benutze es für "Zähle die Anzahl der Antworten> = 2".
Kristen Hammack
3

Josh's Antwort ergänzen,

SELECT COUNT(CASE WHEN myColumn=1 THEN AD_CurrentView.PrimaryKeyColumn ELSE NULL END)
FROM AD_CurrentView

Funktionierte gut für mich (in SQL Server 2012), ohne die 'Anzahl' in eine 'Summe' zu ändern, und dieselbe Logik ist auf andere 'bedingte Aggregate' übertragbar. ZB Summieren basierend auf einer Bedingung:

SELECT SUM(CASE WHEN myColumn=1 THEN AD_CurrentView.NumberColumn ELSE 0 END)
FROM AD_CurrentView
Sturgus
quelle
2

Wie wäre es mit

SELECT id, COUNT(IF status=42 THEN 1 ENDIF) AS cnt
FROM table
GROUP BY table

Kürzer als CASE:)

Funktioniert, weil COUNT()keine Nullwerte gezählt werden und IF/ CASEnull zurückgibt, wenn die Bedingung nicht erfüllt ist und keine vorhanden ist ELSE.

Ich denke, es ist besser als zu benutzen SUM().

maf-soft
quelle
1

Nicht produktspezifisch, aber der SQL-Standard bietet

SELECT COUNT() FILTER WHERE <condition-1>, COUNT() FILTER WHERE <condition-2>, ... FROM ...

für diesen Zweck. Oder etwas, das ihm sehr ähnlich ist, ich weiß es nicht genau.

Und natürlich bleiben Anbieter lieber bei ihren proprietären Lösungen.

Erwin Smout
quelle
1
Ich hatte noch nie davon gehört, also habe ich es nachgeschlagen. Laut modern-sql.com/feature/filterFILTER ist PostgreSQL das einzige wichtige DBMS, das die Klausel tatsächlich anbietet , aber es wird von CASEallen emuliert .
Kristen Hammack
1

Warum nicht so?

SELECT count(1)
FROM AD_CurrentView
WHERE myColumn=1
Michal
quelle
1
Weil er viel mehr braucht als nur die Zählung. Er versucht, die Anzahl der Teile eines Teils einer Gruppe und dann die Gesamtheit der gesamten Gruppe zu ermitteln, was mit einem WO nicht möglich ist.
Kristen Hammack
1

Ich musste COUNTIF () in meinem Fall als Teil meiner SELECT-Spalten verwenden UND um einen Prozentsatz der Häufigkeit nachzuahmen, mit der jedes Element in meinen Ergebnissen angezeigt wurde.

Also habe ich das benutzt ...

SELECT COL1, COL2, ... ETC
       (1 / SELECT a.vcount 
            FROM (SELECT vm2.visit_id, count(*) AS vcount 
                  FROM dbo.visitmanifests AS vm2 
                  WHERE vm2.inactive = 0 AND vm2.visit_id = vm.Visit_ID 
                  GROUP BY vm2.visit_id) AS a)) AS [No of Visits],
       COL xyz
FROM etc etc

Natürlich müssen Sie das Ergebnis entsprechend Ihren Anzeigeanforderungen formatieren.

Fandango68
quelle
-2
SELECT COALESCE(IF(myColumn = 1,COUNT(DISTINCT NumberColumn),NULL),0) column1,
COALESCE(CASE WHEN myColumn = 1 THEN COUNT(DISTINCT NumberColumn) ELSE NULL END,0) AS column2
FROM AD_CurrentView
Andres Sarria
quelle