Aynı tablodaki farklı sütunlar için nasıl sayı alınır?


15

Tablo # 01 Status:

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

Tablo # 02 Claims:

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

Beklenen Sonuç:

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

Sonucu beklendiği gibi alabilmem için sorguyu nasıl yazmam gerekir?

Yanıtlar:


27

En kolay SUM()ve bir CASEaçıklama:

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;

16

Bu tipik bir pivot dönüşümüdür ve Phil tarafından önerildiği gibi koşullu toplama, bunu uygulamanın eski güzel yoludur.

Aynı sonucu elde etmek için PIVOT yan tümcesini kullanan daha modern bir sözdizimi de vardır:

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
;

Dahili olarak bu tartışmasız daha basit görünen sözdizimi Phil'in GROUP BY sorgusuna eşdeğerdir. Daha doğrusu, bu varyasyona eşdeğerdir:

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
;

Bu nedenle, bir PIVOT sorgusu esasen örtülü bir GROUP BY sorgusudur.

Bununla birlikte, PIVOT sorguları, koşullu toplama özelliğine sahip açık GROUP BY sorgularından çok daha karmaşıktır. PIVOT'u kullanırken, daima bu tek şeyi aklınızda bulundurmanız gerekir:

  • Tüm sütunlar veri kümesinin (doğru açılmış Claimsbu durumda) açıkça MİL maddede belirtilen olmadığını GRUBU TARAFINDAN sütunlar bulunmaktadır .

Eğer Claimssizin örnekte görüldüğü yalnızca üç sütun oluşur çünkü görünüşte irade işin üstünde PIVOT sorgu, beklendiği gibi CompanyNameaçıkça PIVOT söylenmeyen tek sütun ve dolayısıyla örtük GROUP BY tek kriter olarak sona erer.

Ancak, Claimsbaşka sütunlar (diyelim ki ClaimDate) varsa, bunlar dolaylı olarak ek GROUP BY sütunları olarak kullanılacaktır - yani, sorgunuz esasen

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

Sonuç büyük olasılıkla istediğiniz gibi olmayacaktır.

Ancak bunu düzeltmek kolaydır. Alakasız sütunların örtülü gruplamaya katılmasını engellemek için, yalnızca sonuç için gereken sütunları seçeceğiniz türetilmiş bir tablo kullanabilirsiniz; ancak bu, sorguyu daha zarif görünmesine neden olur:

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
;

Yine de, Claimszaten türetilmiş bir tablo varsa, başka bir iç içe yerleştirme düzeyi eklemenize gerek yoktur, sadece mevcut türetilmiş tabloda yalnızca çıktıyı üretmek için gereken sütunları seçtiğinizden emin olun.

Kılavuzda PIVOT hakkında daha fazla bilgi edinebilirsiniz:


1

Kuşkusuz tecrübem çoğunlukla MySQL ile ve SQL Server'da fazla zaman geçirmedim. Aşağıdaki sorgu işe yaramazsa çok sürpriz olurdu:

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;

Bu, çıktıyı istediğiniz biçimde vermez, ancak sıfır durumu dışarıda bıraksanız da, istediğiniz tüm bilgileri size verir. Bu benim için biçimlendirme için kullanılıyorsa, özellikle kötü bir fikir gibi görünen bir sorgunun içindeki CASE ifadeleriyle uğraşmaktan çok daha kolay geliyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.