テーブル#01 Status
:
StatusID Status
-----------------------
1 Opened
2 Closed
3 ReOpened
4 Pending
テーブル#02 Claims
:
ClaimID CompanyName StatusID
--------------------------------------
1 ABC 1
2 ABC 1
3 ABC 2
4 ABC 4
5 XYZ 1
6 XYZ 1
期待される結果:
CompanyName TotalOpenClaims TotalClosedClaims TotalReOpenedClaims TotalPendingClaims
--------------------------------------------------------------------------------
ABC 2 1 0 1
XYZ 2 0 0 0
期待どおりの結果を得るには、どのようにクエリを記述する必要がありますか?
SUM()
とCASE
ステートメントを使用するのが最も簡単です。
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によって提案 がそれを実装する古き良き方法です。
同じ結果を得る、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
;
内部的には、この間違いなくシンプルに見える構文は、PhilのGROUP BYクエリと同等です。より正確には、このバリエーションと同等です。
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
;
したがって、PIVOTクエリは本質的に、暗黙のGROUP BYクエリです。
ただし、PIVOTクエリは、条件付き集計を使用した明示的なGROUP BYクエリよりも処理が面倒です。 PIVOTを使用しているときは、常に次のことを覚えておく必要があります。
Claims
))。PIVOT句で明示的に言及されていないはGROUP BY列です。Claims
が例に示されている3つの列のみで構成されている場合、明らかにCompanyName
がPIVOTで明示的に言及されていない唯一の列であり、最終的には暗黙のGROUP BYの唯一の基準。
ただし、Claims
に他の列(たとえば、ClaimDate
)がある場合、それらは暗黙的に追加のGROUP BY列として使用されます。つまり、クエリは基本的に
GROUP BY CompanyName, ClaimDate, ... /* whatever other columns there are*/`
結果はおそらくあなたが望むものではないでしょう。
ただし、これは簡単に修正できます。無関係な列を暗黙的なグループ化に参加させないようにするには、派生テーブルを使用するだけで、結果に必要な列のみを選択できますが、クエリの見栄えが悪くなります。
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
;
それでも、Claims
がすでに派生テーブルである場合は、ネストの別のレベルを追加する必要はありません。現在の派生テーブルで、出力の生成に必要な列のみを選択していることを確認してください。
PIVOTの詳細については、次のマニュアルを参照してください。
確かに私の経験はほとんどMySQLでの経験であり、SQL Serverにあまり時間を費やしていません。次のクエリが機能しない場合、私は非常に驚きます:
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;
これは、希望する形式で出力を提供するわけではありませんが、ゼロのケースを除いて、必要なすべての情報を提供します。これは、クエリ内でCASEステートメントを処理するよりもずっと簡単だと感じます。クエリ内でCASEステートメントをフォーマットに使用するだけの場合は、これは特に悪い考えのように思えます。