Questa è, in un certo senso, un'estensione della soluzione di Lennart , ma è così brutta che non oso suggerirla come una modifica. L'obiettivo qui è ottenere i risultati senza una tabella derivata. Potrebbe non esserci mai la necessità, e combinato con la bruttezza della domanda l'intero sforzo può sembrare uno sforzo sprecato. Volevo comunque fare questo come esercizio, e ora vorrei condividere il mio risultato:
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
;
La parte fondamentale del calcolo è questa (e vorrei prima di tutto notare che l'idea non è mia, ho imparato questo trucco altrove):
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
Questa espressione può essere utilizzata senza alcuna modifica se i valori in Col_B
sono garantiti per non avere mai valori null. Se la colonna può contenere valori null, tuttavia, è necessario tenerne conto, ed è esattamente a questo che serve l' CASE
espressione. Confronta il numero di righe per partizione con il numero di Col_B
valori per partizione. Se i numeri differiscono, significa che alcune righe hanno un valore null inCol_B
e, pertanto, il calcolo iniziale ( DENSE_RANK() ... + DENSE_RANK() - 1
) deve essere ridotto di 1.
Si noti che poiché - 1
fa parte della formula principale, ho scelto di lasciarlo così. Tuttavia, può effettivamente essere incorporato CASE
nell'espressione, nel inutile tentativo di rendere meno brutta l'intera soluzione:
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
;
Questa demo dal vivo su db <> fiddle.uk può essere utilizzata per testare entrambe le varianti della soluzione.