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?

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

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).


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

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

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().


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.


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

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.


-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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.