Jest to typowa transformacja przestawna, a agregacja warunkowa, jak sugeruje Phil , jest dobrym, starym sposobem jej implementacji.
Istnieje również bardziej nowoczesna składnia osiągania tego samego wyniku, która wykorzystuje klauzulę 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
;
Ta wewnętrznie prawdopodobnie znacznie prostsza składnia jest równoważna zapytaniu GROUP BY Phila. Dokładniej, jest to odpowiednik tej odmiany:
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
;
Tak więc zapytanie PIVOT jest zasadniczo niejawnym zapytaniem GROUP BY.
Jednak zapytania PIVOT są znacznie trudniejsze w obsłudze niż jawne zapytania GROUP BY z agregacją warunkową. Korzystając z PIVOT, należy zawsze pamiętać o jednej rzeczy:
- Wszystkie kolumny przestawionego zestawu danych (
Claims
w tym przypadku), które nie są wyraźnie wymienione w klauzuli PIVOT, są kolumnami GROUP BY .
Jeśli Claims
składa się tylko z trzech kolumn pokazanych w twoim przykładzie, powyższe zapytanie PIVOT będzie działać zgodnie z oczekiwaniami, ponieważ najwyraźniej CompanyName
jest to jedyna kolumna, która nie została wyraźnie wymieniona w PIVOT, a zatem kończy się jako jedyne kryterium niejawnej funkcji GROUP BY.
Jeśli jednak Claims
ma inne kolumny (powiedzmy ClaimDate
), zostaną domyślnie użyte jako dodatkowe kolumny GROUP BY - to znaczy, że zapytanie będzie w zasadzie
GROUP BY CompanyName, ClaimDate, ... /* whatever other columns there are*/`
Wynik najprawdopodobniej nie będzie taki, jak chcesz.
Łatwo to jednak naprawić. Aby wykluczyć nieistotne kolumny z udziału w niejawnym grupowaniu, możesz po prostu użyć tabeli pochodnej, w której wybierzesz tylko kolumny potrzebne do wyniku, chociaż to sprawia, że zapytanie jest mniej eleganckie:
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
;
Mimo to, jeśli Claims
jest już tabelą pochodną, nie ma potrzeby dodawania kolejnego poziomu zagnieżdżania, po prostu upewnij się, że w bieżącej tabeli pochodnej wybierasz tylko kolumny wymagane do wygenerowania wyniku.
Możesz przeczytać więcej o PIVOT w instrukcji: