Dies ist in gewisser Weise eine Erweiterung von Lennarts Lösung , aber es ist so hässlich, dass ich es nicht wage, es als Bearbeitung vorzuschlagen. Ziel ist es, die Ergebnisse ohne abgeleitete Tabelle zu erhalten. Möglicherweise besteht dafür nie die Notwendigkeit, und in Verbindung mit der Hässlichkeit der Abfrage scheint das gesamte Unternehmen wie eine vergebliche Anstrengung zu sein. Ich wollte dies dennoch als Übung machen und möchte nun mein Ergebnis teilen:
SELECT
Col_A,
Col_B,
DistinctCount = DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B ASC )
+ DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B DESC)
- 1
- CASE COUNT(Col_B) OVER (PARTITION BY Col_A)
WHEN COUNT( * ) OVER (PARTITION BY Col_A)
THEN 0
ELSE 1
END
FROM
dbo.MyTable
;
Der Kern der Berechnung ist folgender (und ich möchte zunächst darauf hinweisen, dass die Idee nicht meine ist, ich habe an anderer Stelle von diesem Trick erfahren):
DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B ASC )
+ DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B DESC)
- 1
Dieser Ausdruck kann ohne Änderung verwendet werden, wenn Col_B
garantiert ist, dass die Werte in niemals Nullen enthalten. Wenn die Spalte jedoch Nullen enthalten kann, müssen Sie dies berücksichtigen, und genau dafür ist der CASE
Ausdruck da. Es vergleicht die Anzahl der Zeilen pro Partition mit der Anzahl der Col_B
Werte pro Partition. Wenn sich die Zahlen unterscheiden, bedeutet dies, dass einige Zeilen eine Null in haben Col_B
und daher die anfängliche Berechnung ( DENSE_RANK() ... + DENSE_RANK() - 1
) um 1 reduziert werden muss.
Da das - 1
Teil der Kernformel ist, habe ich es so belassen. Es kann jedoch tatsächlich in den CASE
Ausdruck aufgenommen werden, um die gesamte Lösung weniger hässlich erscheinen zu lassen:
SELECT
Col_A,
Col_B,
DistinctCount = DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B ASC )
+ DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B DESC)
- CASE COUNT(Col_B) OVER (PARTITION BY Col_A)
WHEN COUNT( * ) OVER (PARTITION BY Col_A)
THEN 1
ELSE 2
END
FROM
dbo.MyTable
;
Diese Live-Demo auf db <> fiddle.uk kann verwendet werden, um beide Variationen der Lösung zu testen.