By Frank Kalis
Unter den diversen Aggregatfunktionen des T-SQL Arsenals nimmt COUNT() einen einmaligen Platz ein, weil dies die einzige Funtion ist, die "NULL-aware" ist. Das heißt, je nach Verwendung werden NULL Marker berücksichtigt oder nicht.
Beispiel: Wir wollen das Verhältnis "ungefüllter" Zeilen zu "gefüllten" für eine bestimmte Spalte einer Tabelle ermitteln. Auftraggeber für diese packende Aufgabe ist die Qualitätssicherungsabteilung unserer Firma, die den Vorstand davon überzeugt hat, damit eine aussagekräftige Kennzahl zur Hand zu haben.
CREATE TABLE a (c1 int)
INSERT INTO a SELECT 1
UNION all SELECT 2
UNION all SELECT 3
UNION all SELECT 4
UNION all SELECT NULL
Dies ist die Augangsdatenlage. Auf einen Blick erkennt man, daß eine von 5 Zeilen NULL ist, somit der Anteil solcher Zeilen an der Gesamtheit 20% ist. Dies kann man sehr leicht in T-SQL mit Hilfe von COUNT() umsetzen.
SELECT COUNT(*) AS rowcnt
, COUNT(c1) AS non_null
, COUNT(*)-COUNT(c1) AS null_markers
, 1-((COUNT(c1)*1.0)/COUNT(*)) percentage_null_markers
FROM a
rowcnt non_null null_markers percentage_null_markers
----------- ----------- ------------ ---------------------------
5 4 1 .200000000000
(1 row(s) affected)
Warning: Null value is eliminated by an aggregate or other SET operation.
Einfach und vielseitig ohne eigenes Zutun. Spezifiziert man keine Spalte für COUNT, sondern verwendet COUNT(*) werden ALLE Zeilen einer Tabelle gezählt, egal ob NULL oder Duplikat oder was auch immer. Verwendet man hingegen COUNT(< Spaltenname >) werden automatisch NULL Marker nicht mitgezählt. In manchen Situationen kommt einem dieses Verhalten sehr gelegen. Zum Beispiel, wenn man nicht mehr Zeit als nötig auf solche abstrusen Anforderungen verschwenden will. :-)
Natürlich kann man auch eine Alternative wählen. Die sähe dann etwa so aus:
SELECT COUNT(*)
, SUM(CASE WHEN c1 IS NOT NULL THEN 1 ELSE 0 END)
, SUM(CASE WHEN c1 IS NULL THEN 1 ELSE 0 END)
, SUM(CASE WHEN c1 IS NULL THEN 1 ELSE 0 END)*1.0/COUNT(*)
FROM a
----------- ----------- ----------- --------------------------
5 4 1 .200000000000
(1 row(s) affected)
Geschwindigkeitsunterschiede sollten kaum feststellbar sein. Aber, IMHO sieht die erste Alternative eleganter aus.