So ermitteln Sie die Anzahl für verschiedene Spalten in derselben Tabelle

14

Tabelle # 01 Status:

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

Tabelle # 02 Claims:

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

Erwartetes Ergebnis:

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

Wie muss ich die Abfrage schreiben, damit ich das erwartete Ergebnis erhalte?

Kaishu
quelle

Antworten:

26

Am einfachsten geht es mit SUM()und einer CASEAussage:

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ᵀᴹ
quelle
15

Dies ist eine typische Pivot-Transformation und bedingte Aggregation, wie von Phil vorgeschlagen , ist die gute alte Art, sie zu implementieren.

Es gibt auch eine modernere Syntax, um dasselbe Ergebnis zu erzielen, die die PIVOT-Klausel verwendet:

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
;

Intern entspricht diese wohl einfacher aussehende Syntax Phils GROUP BY-Abfrage. Genauer gesagt entspricht es dieser Variante:

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
;

Eine PIVOT-Abfrage ist also im Wesentlichen eine implizite GROUP BY-Abfrage.

PIVOT-Abfragen sind jedoch bekanntermaßen schwieriger zu verarbeiten als explizite GROUP BY-Abfragen mit bedingter Aggregation. Wenn Sie PIVOT verwenden, müssen Sie immer Folgendes beachten:

  • Alle ( Claimsin diesem Fall) geschwenkten Spalten des Datasets, die in der PIVOT-Klausel nicht explizit erwähnt werden, sind GROUP BY-Spalten .

Wenn Claimsin Ihrem Beispiel nur drei Spalten angezeigt werden, funktioniert die obige PIVOT-Abfrage anscheinend wie erwartetCompanyName die einzige in PIVOT nicht explizit erwähnte Spalte ist und somit das einzige Kriterium für die implizite GROUP BY ist.

Wenn Claimsjedoch andere Spalten vorhanden sind (z. B. ClaimDate), werden diese implizit als zusätzliche GROUP BY-Spalten verwendet. Dies ist im Wesentlichen die Aufgabe Ihrer Abfrage

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

Das Ergebnis wird höchstwahrscheinlich nicht das sein, was Sie wollen.

Das ist jedoch leicht zu beheben. Um irrelevante Spalten von der Teilnahme an der impliziten Gruppierung auszuschließen, können Sie einfach eine abgeleitete Tabelle verwenden, in der Sie nur die für das Ergebnis erforderlichen Spalten auswählen, obwohl die Abfrage dadurch weniger elegant aussieht:

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
;

Trotzdem, wenn Claims es sich jedoch bereits um eine abgeleitete Tabelle handelt, muss keine weitere Verschachtelungsebene hinzugefügt werden. Stellen Sie lediglich sicher, dass Sie in der aktuellen abgeleiteten Tabelle nur die Spalten auswählen, die für die Ausgabe erforderlich sind.

Weitere Informationen zu PIVOT finden Sie im Handbuch:

Andriy M
quelle
1

Zugegeben, ich habe hauptsächlich Erfahrung mit MySQL und habe nicht viel Zeit mit SQL Server verbracht. Ich wäre sehr überrascht, wenn die folgende Abfrage nicht funktioniert hätte:

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;

Dadurch erhalten Sie nicht die Ausgabe in dem gewünschten Format, aber Sie erhalten alle gewünschten Informationen, auch wenn die Null-Fälle weggelassen werden. Das fühlt sich für mich viel einfacher an, als mit CASE-Anweisungen innerhalb einer Abfrage umzugehen, die sich als besonders schlechte Idee anfühlen, wenn sie nur zum Formatieren verwendet werden.

Harageth
quelle