Cómo obtener el recuento de diferentes columnas en la misma tabla


15

Tabla # 01 Status:

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

Tabla # 02 Claims:

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

Resultado Esperado:

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

¿Cómo necesito escribir la consulta para poder obtener el resultado como se esperaba?

Respuestas:


26

Es más fácil con SUM()y una CASEdeclaración:

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

Esta es una transformación pivote típica, y la agregación condicional, como lo sugirió Phil , es la buena forma de implementarla.

También hay una sintaxis más moderna para lograr el mismo resultado, que utiliza la cláusula 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, esta sintaxis de apariencia más simple es equivalente a la consulta GROUP BY de Phil. Más exactamente, es equivalente a esta variación:

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
;

Entonces, una consulta PIVOT es esencialmente una consulta GROUP BY implícita.

Sin embargo, las consultas PIVOT son notoriamente más difíciles de manejar que las consultas explícitas GROUP BY con agregación condicional. Cuando usa PIVOT, siempre debe tener en cuenta lo siguiente:

  • Todas las columnas del conjunto de datos que se pivotan ( Claimsen este caso) que no se mencionan explícitamente en la cláusula PIVOT son columnas GROUP BY .

Si Claimsconsta solo de las tres columnas que se muestran en su ejemplo, la consulta PIVOT anterior funcionará como se esperaba, porque aparentemente CompanyNamees la única columna que no se menciona explícitamente en PIVOT y, por lo tanto, termina siendo el único criterio del GROUP BY implícito.

Sin embargo, si Claimstiene otras columnas (por ejemplo, ClaimDate), se utilizarán implícitamente como columnas GROUP BY adicionales, es decir, su consulta esencialmente estará haciendo

GROUP BY CompanyName, ClaimDate, ... /* whatever other columns there are*/`

El resultado probablemente no sea lo que quieres.

Sin embargo, eso es fácil de arreglar. Para excluir a las columnas irrelevantes de participar en la agrupación implícita, solo puede usar una tabla derivada, donde seleccionará solo las columnas necesarias para el resultado, aunque eso hace que la consulta tenga un aspecto menos 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
;

Aún así, si Claimsya es una tabla derivada, no es necesario agregar otro nivel de anidamiento, solo asegúrese de que en la tabla derivada actual esté seleccionando solo las columnas necesarias para producir el resultado.

Puede leer más sobre PIVOT en el manual:


1

Es cierto que mi experiencia es con MySQL principalmente y no he pasado mucho tiempo en SQL Server. Me sorprendería mucho si la siguiente consulta no funcionara:

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;

Esto no le proporciona la salida en el formato que desea, pero le brinda toda la información que desea, aunque omite los cero casos. Esto me parece mucho más simple que tratar con declaraciones CASE dentro de una consulta, lo que parece una idea especialmente mala si solo se usa para formatear.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.