Essa é uma transformação de pivô típica e a agregação condicional, como sugerido por Phil , é a boa e velha maneira de implementá-la.
Há também uma sintaxe mais moderna de obter o mesmo resultado, que usa a 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, essa sintaxe aparentemente mais simples é equivalente à consulta GROUP BY de Phil. Mais exatamente, é equivalente a esta variação:
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
;
Portanto, uma consulta PIVOT é uma consulta GROUP BY implícita, essencialmente.
As consultas PIVOT, no entanto, são notoriamente mais complicadas no manuseio do que as consultas explícitas GROUP BY com agregação condicional. Ao usar o PIVOT, você sempre deve ter em mente o seguinte:
- Todas as colunas do conjunto de dados que estão sendo dinâmicas (
Claims
neste caso) que não são explicitamente mencionadas na cláusula PIVOT são colunas GROUP BY .
Se Claims
consistir apenas nas três colunas mostradas no seu exemplo, a consulta PIVOT acima funcionará conforme o esperado, porque aparentemente CompanyName
é a única coluna não mencionada explicitamente no PIVOT e, portanto, acaba como o único critério do GROUP BY implícito.
No entanto, se Claims
houver outras colunas (digamos ClaimDate
), elas serão implicitamente usadas como colunas GROUP BY adicionais - ou seja, sua consulta estará essencialmente funcionando
GROUP BY CompanyName, ClaimDate, ... /* whatever other columns there are*/`
O resultado provavelmente não será o que você deseja.
Isso é fácil de corrigir, no entanto. Para excluir colunas irrelevantes da participação no agrupamento implícito, você pode apenas usar uma tabela derivada, na qual você selecionará apenas as colunas necessárias para o resultado, embora isso torne a consulta 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
;
Ainda, se Claims
já é uma tabela derivada, não há necessidade de adicionar outro nível de aninhamento, apenas certifique-se de que na tabela derivada atual você esteja selecionando apenas as colunas necessárias para produzir a saída.
Você pode ler mais sobre o PIVOT no manual: