Cara mendapatkan hitungan untuk berbagai kolom di tabel yang sama

14

Tabel # 01 Status:

StatusID    Status
-----------------------
 1          Opened
 2          Closed
 3          ReOpened
 4          Pending

Tabel # 02 Claims:

ClaimID     CompanyName StatusID
--------------------------------------
1               ABC     1
2               ABC     1
3               ABC     2
4               ABC     4
5               XYZ     1
6               XYZ     1

Hasil yang diharapkan:

CompanyName TotalOpenClaims TotalClosedClaims TotalReOpenedClaims TotalPendingClaims
--------------------------------------------------------------------------------
ABC                 2           1                      0               1
XYZ                 2           0                      0               0

Bagaimana saya harus menulis kueri sehingga saya bisa mendapatkan hasil seperti yang diharapkan?

Kaishu
sumber

Jawaban:

26

Ini paling mudah dengan SUM()dan CASEpernyataan:

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;
Philᵀᴹ
sumber
15

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 ( Claimsdalam hal ini) yang tidak disebutkan secara eksplisit dalam klausa PIVOT adalah kolom GROUP BY .

Jika Claimshanya terdiri dari tiga kolom yang ditunjukkan dalam contoh Anda, kueri PIVOT di atas akan berfungsi seperti yang diharapkan, karena tampaknya CompanyNameadalah satu-satunya kolom yang tidak secara eksplisit disebutkan dalam PIVOT dan dengan demikian berakhir sebagai satu-satunya kriteria dari GROUP BY implisit.

Namun, jika Claimsmemiliki 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 Claimssudah 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:

Andriy M
sumber
1

Memang pengalaman saya dengan MySQL kebanyakan dan saya belum menghabiskan banyak waktu di SQL Server. Saya akan sangat terkejut jika kueri berikut tidak berfungsi:

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;

Ini tidak memberi Anda output dalam format yang Anda inginkan tetapi itu memberi Anda semua informasi yang Anda inginkan, meskipun meninggalkan nol kasus. Ini terasa jauh lebih sederhana bagi saya daripada berurusan dengan pernyataan KASUS di dalam kueri yang terasa seperti ide yang sangat buruk jika hanya digunakan untuk memformat.

Harageth
sumber