Ini, dengan cara tertentu, merupakan perluasan dari solusi Lennart , tetapi sangat jelek sehingga saya tidak berani menyarankannya sebagai hasil edit. Tujuannya di sini adalah untuk mendapatkan hasil tanpa tabel turunan. Mungkin tidak pernah ada kebutuhan untuk itu, dan dikombinasikan dengan keburukan dari permintaan, seluruh upaya itu mungkin tampak seperti usaha yang sia-sia. Saya masih ingin melakukan ini sebagai latihan, dan sekarang ingin membagikan hasil saya:
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
;
Bagian inti dari perhitungan adalah ini (dan pertama-tama saya ingin mencatat bahwa idenya bukan milik saya, saya belajar tentang trik ini di tempat lain):
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
Ekspresi ini dapat digunakan tanpa perubahan apa pun jika nilai dalam Col_B
dijamin tidak pernah memiliki null. Namun, jika kolom memiliki nol, Anda harus memperhitungkannya, dan itulah tepatnya yang dimaksud dengan CASE
ekspresi itu. Ini membandingkan jumlah baris per partisi dengan jumlah Col_B
nilai per partisi. Jika angkanya berbeda, itu berarti bahwa beberapa baris memiliki nol Col_B
dan, oleh karena itu, perhitungan awal ( DENSE_RANK() ... + DENSE_RANK() - 1
) perlu dikurangi dengan 1.
Perhatikan bahwa karena - 1
ini adalah bagian dari formula inti, saya memilih untuk membiarkannya seperti itu. Namun, itu sebenarnya dapat dimasukkan ke dalam CASE
ekspresi, dalam upaya yang sia-sia untuk membuat seluruh solusi terlihat kurang jelek:
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
;
Demo langsung ini di db <> fiddle.uk dapat digunakan untuk menguji kedua variasi solusi.