Come ottenere il conteggio per colonne diverse sulla stessa tabella


15

Tabella n. 01 Status:

StatusID    Status
-----------------------
 1          Opened
 2          Closed
 3          ReOpened
 4          Pending

Tabella n. 02 Claims:

ClaimID     CompanyName StatusID
--------------------------------------
1               ABC     1
2               ABC     1
3               ABC     2
4               ABC     4
5               XYZ     1
6               XYZ     1

Risultato atteso:

CompanyName TotalOpenClaims TotalClosedClaims TotalReOpenedClaims TotalPendingClaims
--------------------------------------------------------------------------------
ABC                 2           1                      0               1
XYZ                 2           0                      0               0

Come devo scrivere la query per poter ottenere il risultato come previsto?

Risposte:


26

È più facile con SUM()e una CASEdichiarazione:

select CompanyName, 
sum(case when StatusID=1 then 1 else 0 end) as TotalOpenClaims,
sum(case when StatusID=2 then 1 else 0 end) as TotalClosedClaims,
sum(case when StatusID=3 then 1 else 0 end) as TotalReOpenedClaims,
sum(case when StatusID=4 then 1 else 0 end) as TotalPendingClaims
from Claims
group by CompanyName;

16

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 ( Claimsin questo caso) che non sono esplicitamente menzionate nella clausola PIVOT sono colonne GROUP BY .

Se è Claimscostituito 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 Claimsha 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:


1

Devo ammettere che la mia esperienza è principalmente con MySQL e non ho trascorso molto tempo su SQL Server. Sarei molto sorpreso se la seguente query non funzionasse:

SELECT 
  CompanyName, 
  status, 
  COUNT(status) AS 'Total Claims' 
FROM Claim AS c 
  JOIN Status AS s ON c.statusId = s.statusId 
GROUP BY 
  CompanyName, 
  status;

Questo non ti dà l'output nel formato che desideri, ma ti dà tutte le informazioni che desideri, anche se tralasciando i casi zero. Questo mi sembra molto più semplice rispetto alle istruzioni CASE all'interno di una query che sembrano un'idea particolarmente negativa se viene utilizzata solo per la formattazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.