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_Bgwarantowane 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 CASEsłuży wyrażenie. Porównuje liczbę wierszy na partycję z liczbą Col_Bwartoś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ż - 1jest to część podstawowej formuły, postanowiłem tak to zostawić. Można go jednak włączyć do CASEwyraż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.