Jest to w pewnym sensie rozszerzenie rozwiązania Lennarta , ale jest tak brzydkie, że nie śmiem sugerować go jako edycji. Celem jest uzyskanie wyników bez tabeli pochodnej. Może nigdy nie będzie takiej potrzeby, a w połączeniu z brzydotą zapytania całe przedsięwzięcie może wydawać się zmarnowanym wysiłkiem. Nadal chciałem to zrobić jako ćwiczenie i chciałbym teraz podzielić się moim wynikiem:
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
;
Podstawowa część obliczeń jest następująca (i przede wszystkim chciałbym zauważyć, że pomysł nie jest mój, dowiedziałem się o tej sztuczce gdzie indziej):
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
Tego wyrażenia można używać bez żadnych zmian, jeśli Col_B
gwarantowane wartości nigdy nie będą miały wartości null. Jeśli jednak kolumna może mieć wartości null, należy to uwzględnić, i właśnie do tego CASE
służy wyrażenie. Porównuje liczbę wierszy na partycję z liczbą Col_B
wartości na partycję. Jeśli liczby się różnią, oznacza to, że niektóre wiersze mają wartość null Col_B
, dlatego wstępne obliczenia ( DENSE_RANK() ... + DENSE_RANK() - 1
) należy zmniejszyć o 1.
Zauważ, że ponieważ - 1
jest to część podstawowej formuły, postanowiłem tak to zostawić. Można go jednak włączyć do CASE
wyrażenia w bezskutecznej próbie sprawienia, by całe rozwiązanie wyglądało mniej brzydko:
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
;
To demo na żywo w db <> fiddle.uk może być użyte do przetestowania obu wariantów rozwiązania.