Cách lấy số lượng cho các cột khác nhau trên cùng một bảng


14

Bảng số 01 Status:

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

Bảng số 02 Claims:

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

Kết quả dự kiến:

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

Làm thế nào để tôi cần viết truy vấn để tôi có thể nhận được kết quả như mong đợi?

Câu trả lời:


26

Nó dễ nhất với SUM()và một CASEtuyên bố:

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;

15

Đây là một chuyển đổi trục điển hình và tổng hợp có điều kiện, như đề xuất của Phil , là cách tốt để thực hiện nó.

Ngoài ra còn có một cú pháp hiện đại hơn để đạt được kết quả tương tự, sử dụng mệnh đề 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
;

Trong nội bộ cú pháp tìm kiếm đơn giản hơn này có thể tương đương với truy vấn GROUP BY của Phil. Chính xác hơn, nó tương đương với biến thể này:

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
;

Vì vậy, về cơ bản, một truy vấn PIVOT là một truy vấn GROUP BY ẩn.

Tuy nhiên, các truy vấn PIVOT nổi tiếng là khó xử lý hơn các truy vấn GROUP BY rõ ràng với tổng hợp có điều kiện. Khi bạn đang sử dụng PIVOT, bạn cần luôn ghi nhớ điều này:

  • Tất cả các cột của bộ dữ liệu được xoay vòng ( Claimstrong trường hợp này) không được đề cập rõ ràng trong mệnh đề PIVOT là các cột GROUP BY .

Nếu chỉ Claimsbao gồm ba cột được hiển thị trong ví dụ của bạn, truy vấn PIVOT ở trên sẽ hoạt động như mong đợi, vì rõ ràng CompanyNamelà cột duy nhất không được đề cập rõ ràng trong PIVOT và do đó kết thúc là tiêu chí duy nhất của NHÓM ẩn.

Tuy nhiên, nếu Claimscó các cột khác (giả sử ClaimDate), chúng sẽ hoàn toàn được sử dụng làm các cột NHÓM B BYNG bổ sung - nghĩa là, truy vấn của bạn về cơ bản sẽ được thực hiện

GROUP BY CompanyName, ClaimDate, ... /* whatever other columns there are*/`

Kết quả rất có thể sẽ không như những gì bạn muốn.

Đó là dễ dàng để sửa chữa, mặc dù. Để loại trừ các cột không liên quan tham gia vào nhóm ẩn, bạn chỉ có thể sử dụng bảng dẫn xuất, trong đó bạn sẽ chỉ chọn các cột cần thiết cho kết quả, mặc dù điều đó làm cho truy vấn trông kém thanh lịch:

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
;

Tuy nhiên, nếu Claimsđã là một bảng dẫn xuất, không cần thêm một mức lồng nhau khác, chỉ cần đảm bảo rằng trong bảng dẫn xuất hiện tại bạn chỉ chọn các cột cần thiết để tạo đầu ra.

Bạn có thể đọc thêm về PIVOT trong hướng dẫn:


1

Phải thừa nhận rằng trải nghiệm của tôi là với MySQL và tôi đã không dành nhiều thời gian cho SQL Server. Tôi sẽ rất ngạc nhiên nếu truy vấn sau không hoạt động:

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;

Điều này không cung cấp cho bạn đầu ra ở định dạng mà bạn muốn nhưng nó cung cấp cho bạn tất cả thông tin bạn muốn, mặc dù không có trường hợp nào. Điều này đối với tôi đơn giản hơn nhiều so với việc xử lý các câu lệnh CASE bên trong một truy vấn có cảm giác như một ý tưởng đặc biệt tồi tệ nếu nó chỉ được sử dụng để định dạng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.