Це, певним чином, розширення до рішення Леннарта , але воно настільки потворне, що я не смію пропонувати це як редагування. Мета тут - отримати результати без похідної таблиці. Ніколи в цьому не може бути потреби, і в поєднанні з неподобством запиту все починання може здатися марним зусиллям. Я все-таки хотів це зробити як вправу, і зараз хотів би поділитися своїм результатом:
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
;
Основна частина розрахунку полягає в цьому (і я, перш за все, хотів би зазначити, що ідея не моя, я дізнався про цю хитрість в інших місцях):
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
Цей вираз може бути використаний без будь-яких змін, якщо значення в Col_B
гарантовано ніколи не матимуть нулів. Однак, якщо стовпець може мати нулі, вам потрібно це врахувати, і саме для цього CASE
є вираз. Він порівнює кількість рядків на розділ з кількістю Col_B
значень на розділ. Якщо цифри відрізняються, це означає, що деякі рядки мають нульове значення, Col_B
і, отже, початковий обчислення ( DENSE_RANK() ... + DENSE_RANK() - 1
) потрібно зменшити на 1.
Зауважте, що оскільки - 1
це частина основної формули, я вирішив залишити її так. Однак він може бути фактично включений у CASE
вираз, у марній спробі зробити все рішення менш потворним:
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
;
Цей демонстраційний файл на db <> fiddle.uk можна використовувати для тестування обох варіантів рішення.