Il s'agit d'une transformation de pivot typique, et l'agrégation conditionnelle, comme suggéré 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:
- Toutes les colonnes de l'ensemble de données pivoté (
Claims
dans ce cas) qui ne sont pas explicitement mentionnées dans la clause PIVOT sont des colonnes GROUP BY .
Si se Claims
compose uniquement des trois colonnes illustrées dans votre exemple, la requête PIVOT ci-dessus fonctionnera comme prévu, car apparemment, CompanyName
c'est la seule colonne non explicitement mentionnée dans PIVOT et se retrouve donc comme le seul critère du GROUP BY implicite.
Cependant, si elle Claims
contient 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, s'il Claims
existe 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: