Questa è una tipica trasformazione a perno e l'aggregazione condizionale, come suggerito da Phil , è il buon vecchio modo di implementarla.
Esiste anche una sintassi più moderna per ottenere lo stesso risultato, che utilizza la clausola PIVOT:
SELECT
CompanyName,
TotalOpenClaims = [1],
TotalClosedClaims = [2],
TotalReOpenedClaims = [3],
TotalPendingClaims = [4]
FROM
dbo.Claims
PIVOT
(
COUNT(ClaimID)
FOR StatusID IN ([1], [2], [3], [4])
) AS p
;
Internamente questa sintassi dall'aspetto probabilmente più semplice equivale alla query GROUP BY di Phil. Più esattamente, è equivalente a questa variazione:
SELECT
CompanyName,
TotalOpenClaims = COUNT(CASE WHEN StatusID = 1 THEN ClaimID END),
TotalClosedClaims = COUNT(CASE WHEN StatusID = 2 THEN ClaimID END),
TotalReOpenedClaims = COUNT(CASE WHEN StatusID = 3 THEN ClaimID END),
TotalPendingClaims = COUNT(CASE WHEN StatusID = 4 THEN ClaimID END)
FROM
dbo.Claims
GROUP BY
CompanyName
;
Pertanto, una query PIVOT è essenzialmente una query GROUP BY implicita.
Le query PIVOT, tuttavia, sono notoriamente più difficili da gestire rispetto alle query GROUP BY esplicite con aggregazione condizionale. Quando si utilizza PIVOT, è necessario tenere sempre presente questa cosa:
- Tutte le colonne del set di dati in fase di pivot (
Claims
in questo caso) che non sono esplicitamente menzionate nella clausola PIVOT sono colonne GROUP BY .
Se è Claims
costituito solo dalle tre colonne mostrate nel tuo esempio, la query PIVOT sopra funzionerà come previsto, perché apparentemente CompanyName
è l'unica colonna non esplicitamente menzionata in PIVOT e finisce quindi come l'unico criterio dell'implicito GROUP BY.
Tuttavia, se Claims
ha altre colonne (ad esempio, ClaimDate
), verranno implicitamente utilizzate come colonne GROUP BY aggiuntive, ovvero la query essenzialmente eseguirà
GROUP BY CompanyName, ClaimDate, ... /* whatever other columns there are*/`
Molto probabilmente il risultato non sarà quello che vuoi.
È facile da risolvere, però. Per escludere le colonne irrilevanti dalla partecipazione al raggruppamento implicito, puoi semplicemente utilizzare una tabella derivata, in cui selezionerai solo le colonne necessarie per il risultato, sebbene ciò renda la query meno elegante:
SELECT
CompanyName,
TotalOpenClaims = [1],
TotalClosedClaims = [2],
TotalReOpenedClaims = [3],
TotalPendingClaims = [4]
FROM
(SELECT ClaimID, CompanyName, StatusID FROM dbo.Claims) AS derived
PIVOT
(
COUNT(ClaimID)
FOR StatusID IN ([1], [2], [3], [4])
) AS p
;
Tuttavia, se Claims
è già una tabella derivata, non è necessario aggiungere un altro livello di annidamento, ma accertarsi che nella tabella derivata corrente si selezionino solo le colonne necessarie per produrre l'output.
Puoi leggere di più su PIVOT nel manuale: