Tableau # 01 Status
:
StatusID Status
-----------------------
1 Opened
2 Closed
3 ReOpened
4 Pending
Tableau # 02 Claims
:
ClaimID CompanyName StatusID
--------------------------------------
1 ABC 1
2 ABC 1
3 ABC 2
4 ABC 4
5 XYZ 1
6 XYZ 1
Résultat attendu:
CompanyName TotalOpenClaims TotalClosedClaims TotalReOpenedClaims TotalPendingClaims
--------------------------------------------------------------------------------
ABC 2 1 0 1
XYZ 2 0 0 0
Comment dois-je écrire la requête afin d'obtenir le résultat attendu?
C'est plus simple avec SUM()
et une instruction CASE
:
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;
Il s'agit d'une transformation de pivot typique, et l'agrégation conditionnelle, comme suggérée par Phil , est la bonne vieille façon de l'implémenter.
Il existe également une syntaxe plus moderne pour obtenir le même résultat, qui utilise la clause 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
;
En interne, cette syntaxe sans doute plus simple est équivalente à la requête GROUP BY de Phil. Plus exactement, elle équivaut à cette variation:
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
;
Ainsi, une requête PIVOT est une requête GROUP BY implicite, essentiellement.
Les requêtes PIVOT, cependant, sont notoirement plus difficiles à gérer que les requêtes GROUP BY explicites avec agrégation conditionnelle. Lorsque vous utilisez PIVOT, vous devez toujours garder à l'esprit cette seule chose:
Claims
dans ce cas) qui ne sont pas explicitement mentionnées dans la clause PIVOT sont des colonnes GROUP BY .Si Claims
se compose uniquement des trois colonnes illustrées dans votre exemple, la requête PIVOT ci-dessus fonctionnera comme prévu, car apparemment CompanyName
est la seule colonne non explicitement mentionnée dans PIVOT et se retrouve donc comme seul critère du GROUP BY implicite.
Cependant, si Claims
a d'autres colonnes (disons, ClaimDate
), elles seront implicitement utilisées comme colonnes GROUP BY supplémentaires - c'est-à-dire que votre requête fera essentiellement
GROUP BY CompanyName, ClaimDate, ... /* whatever other columns there are*/`
Le résultat ne sera probablement pas ce que vous voulez.
C'est facile à résoudre, cependant. Afin d'exclure les colonnes non pertinentes de la participation au regroupement implicite, vous pouvez simplement utiliser une table dérivée, où vous ne sélectionnerez que les colonnes nécessaires au résultat, bien que cela rend la requête moins élégante:
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
;
Néanmoins, si Claims
est déjà une table dérivée, il n'est pas nécessaire d'ajouter un autre niveau d'imbrication, assurez-vous simplement que dans la table dérivée actuelle, vous ne sélectionnez que les colonnes requises pour produire la sortie.
Vous pouvez en savoir plus sur PIVOT dans le manuel:
Certes, mon expérience concerne principalement MySQL et je n'ai pas passé beaucoup de temps sur SQL Server. Je serais très surpris si la requête suivante ne fonctionnait pas:
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;
Cela ne vous donne pas la sortie dans le format que vous voulez mais cela vous donne toutes les informations que vous voulez, même si vous omettez les cas zéro. Cela me semble beaucoup plus simple que de traiter des instructions CASE à l'intérieur d'une requête, ce qui semble être une idée particulièrement mauvaise si elle est simplement utilisée pour le formatage.