Ini adalah transformasi pivot yang khas, dan agregasi bersyarat, seperti yang disarankan oleh Phil , adalah cara lama yang baik untuk mengimplementasikannya.
Ada juga sintaksis yang lebih modern untuk mencapai hasil yang sama, yang menggunakan klausa 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
;
Secara internal, sintaks yang terlihat lebih sederhana ini setara dengan kueri GROUP BY. Lebih tepatnya, ini setara dengan variasi ini:
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
;
Jadi, permintaan PIVOT adalah permintaan GROUP BY implisit, pada dasarnya.
Namun, pertanyaan PIVOT terkenal lebih sulit dalam penanganannya daripada kueri GROUP BY yang eksplisit dengan agregasi bersyarat. Saat Anda menggunakan PIVOT, Anda harus selalu mengingat satu hal ini:
- Semua kolom dataset sedang diputar (
Claims
dalam hal ini) yang tidak disebutkan secara eksplisit dalam klausa PIVOT adalah kolom GROUP BY .
Jika Claims
hanya terdiri dari tiga kolom yang ditunjukkan dalam contoh Anda, kueri PIVOT di atas akan berfungsi seperti yang diharapkan, karena tampaknya CompanyName
adalah satu-satunya kolom yang tidak secara eksplisit disebutkan dalam PIVOT dan dengan demikian berakhir sebagai satu-satunya kriteria dari GROUP BY implisit.
Namun, jika Claims
memiliki kolom lain (misalnya, ClaimDate
), mereka akan secara implisit digunakan sebagai kolom GROUP BY tambahan - yaitu, permintaan Anda pada dasarnya akan melakukan
GROUP BY CompanyName, ClaimDate, ... /* whatever other columns there are*/`
Hasilnya kemungkinan besar tidak seperti yang Anda inginkan.
Itu mudah diperbaiki. Untuk mengecualikan kolom yang tidak relevan dari berpartisipasi dalam pengelompokan implisit, Anda bisa menggunakan tabel turunan, di mana Anda hanya akan memilih kolom yang diperlukan untuk hasil, meskipun itu membuat kueri tampak kurang elegan:
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
;
Namun, jika Claims
sudah merupakan tabel turunan, tidak perlu menambahkan level lain untuk bersarang, cukup pastikan bahwa dalam tabel turunan saat ini Anda hanya memilih kolom yang diperlukan untuk menghasilkan output.
Anda dapat membaca lebih lanjut tentang PIVOT dalam manual: