問題を例を挙げて説明します。
私が行った引き出しプロセスを選択して表示し、預金残高のステータスを表示するクエリ。
列
Deposit
、TotalAmount
を含むテーブルDepositDate
が作成されます。列
Withdrawal
、WithdrawAmount
を含む別のテーブルWithdrawDate
が作成されます。
したがって、SELECTクエリを使用して、式を使用して両方のテーブルから選択します。
_SELECT WithdrawAmount,
CASE WHEN ( TotalAmount - WithdrawAmount) = 0 THEN 'ZeroBalanceOops'
ELSE 'StillAvailableYAY' as 'Status'
FROM Deposit Inner Join Withdraw WHERE [WithdrawDate] between this month beginning and ending
_
したがって、このクエリでは、500のデポジットがあり、一度だけデポジットするとします。今月に一度だけ引き落とし、預金を完全に引き落とすとうまくいきます。結果は次のようになります。
_| WithdrawAmount | Status |
| 500 | ZeroBalanceOops |
_
ただし、1か月に2回以上引き出した場合は機能しません。これらの引き出しにより残高は0になります。預金が再び500であるとすると、結果は次のようになります。
_| WithdrawAmount | Status |
| 250 | StillAvailableYAY |
| 250 | StillAvailableYAY |
_
期待される結果は、最初の引き出しで「StillAvailableYAY」、次に2番目の引き出しステータスで「ZeroBalanceOops」になることですが、比較するのは_500-250
_だけではなく_500-250-250
_なので、常に「StillAvailableYAY」ステータスになります。 SUM(WithdrawalAmount)
を使用しても、2つの引き出しのステータスが「ZeroBalanceOops」になるため、希望する結果が得られません。
以前に選択したクエリを取得して計算に含めるにはどうすればよいですか?それとも、もっと良い方法はありますか?
これは「積算合計」タイプの問題です。各行の合計は、前の行の合計に追加または減算されたその行の値に基づいて計算されます。
SQL Server 2014を使用しているため、Transact-SQLには、結果の取得に役立つ組み込みの構文が用意されています。
「1か月に1回のデポジット、1か月に多くの引き出し」という単純なモデルを使用すると、SQLステートメントは次のようになります。
_SELECT
d.TotalAmount,
w.WithdrawAmount,
Balance = d.TotalAmount - SUM(w.WithdrawAmount) OVER (ORDER BY w.WithdrawDate ASC)
FROM
dbo.Deposit AS d,
dbo.Withdrawal AS w
WHERE
d.DepositDate >= start_of_this_month AND d.DepositDate < start_of_next_month
AND
w.WithdrawDate >= start_of_this_month AND w.WithdrawDate < start_of_next_month
;
_
WHERE句は、Deposit
からの1つの入金行と、Withdrawal
からの対応する多数の引き出しにテーブルをフィルタリングすることになっています。テーブルが複数のアカウントをサポートし、金額をアカウントごとにさらに関連付ける必要がある場合は、FROM句を次のように置き換えることができます。
_FROM
dbo.Deposit AS d
INNER JOIN dbo.Withdrawal AS w ON d.AccountNumber = w.AccountNumber
_
SUM(w.WithdrawAmount) OVER (ORDER BY w.WithdrawDate ASC)
式は、各行の実行中のWithdrawAmount
合計を計算します。したがって、合計は各行で増加します(WithdrawDate
の昇順で並べ替えられます)。したがって、各行でTotalAmount
から増加する量が減算され、Balance
が0に近づきます。
上記のクエリは、各行の残高を提供しますが、ステータスは提供しません。ステータスを取得するには、Balance
値を参照して0と比較し、対応するステータス文字列を選択して返す必要があります。 Balance
は計算列であり、それを参照できるようにするには、上記のクエリをネストして、外部レベルでBalance
を参照する必要があります。ネストは、派生テーブルまたは共通テーブル式(CTE)のいずれかで行うことができます。このクエリはCTEを使用します。
_WITH balances AS
(
SELECT
d.TotalAmount,
w.WithdrawAmount,
Balance = d.TotalAmount - SUM(w.WithdrawAmount) OVER (ORDER BY w.WithdrawDate ASC)
FROM
dbo.Deposit AS d,
dbo.Withdrawal AS w
WHERE
d.DepositDate >= start_of_this_month AND d.DepositDate < start_of_next_month
AND
w.WithdrawDate >= start_of_this_month AND w.WithdrawDate < start_of_next_month
)
SELECT
TotalAmount,
WithdrawAmount,
Balance,
Status = CASE WHEN Balance > 0 THEN 'StillAvailableYAY' ELSE 'ZeroBalanceOops' END
FROM
balances
;
_
もちろん、本当に残高を返す必要がない場合、それを0と比較するだけの場合は、入れ子にする必要はなく、d.TotalAmount - SUM(w.WithdrawAmount) OVER (ORDER BY w.WithdrawDate ASC)
式をCASEに直接入れて、Balance
を置き換えることができます。