Je vais expliquer le problème avec un exemple.
Une requête qui sélectionnera et montrent le processus de retrait que j'ai fabriqué et montrez le statut de mon solde de dépôt.
Une table
Deposit
est créée avec des colonnesTotalAmount
,DepositDate
.Une autre table
Withdrawal
est créée avec des colonnesWithdrawAmount
,WithdrawDate
.
J'utilise donc une requête sélectionnée pour sélectionner les deux tables avec des formules:
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
Donc, pour cette requête, supposons que j'ai un acompte de 500 et ne se déposera qu'une seule fois. Cela fonctionne bien si je ne retire qu'une seule fois ce mois-ci et retire complètement le dépôt. Le résultat montrera comme ceci:
| WithdrawAmount | Status |
| 500 | ZeroBalanceOops |
Cependant, cela ne fonctionne pas si je retire plus d'une fois par mois et que ces retraits feraient la balance = 0. En supposant que le dépôt soit de 500, le résultat montrerait comme ceci:
| WithdrawAmount | Status |
| 250 | StillAvailableYAY |
| 250 | StillAvailableYAY |
Le résultat attendu est d'avoir "stillavailableyay" au premier sevrage, puis "Zerobalanceoops" au deuxième état de sevrage, mais il ne compare que 500-250
Non 500-250-250
Ce sera toujours le statut "Stillavailableyay". À l'aide de SUM(WithdrawalAmount)
ne donne pas le résultat que je veux, car cela ferait que les deux retraits disposent de "Zerobalanceoops".
Une idée de la manière dont puis-je récupérer la requête précédemment sélectionnée et l'inclure dans le calcul? Ou y a-t-il un meilleur moyen de le faire?
Il s'agit d'un type de problème "total d'exécution": le total de chaque ligne est calculé sur la base de la valeur ajoutée de cette ligne ou soustraite du total de la ligne précédente.
Depuis que vous utilisez SQL Server 2014, Transact-SQL possède une syntaxe intégrée à votre disposition pour vous aider à obtenir les résultats.
Utilisation du modèle simplifié de "Un dépôt par mois, de nombreux retraits par mois", la déclaration SQL pourrait aller comme ceci:
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
;
La clause WHERE est censée filtrer les tables à une ligne de dépôt de Deposit
et de nombreux retraits correspondants de Withdrawal
. Si les tableaux prennent en charge plusieurs comptes et que les montants doivent être davantage liés par compte, vous voudrez peut-être remplacer la clause de quelque chose comme ceci:
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)
expression calcule une exécution WithdrawAmount
total pour chaque ligne. Donc, le total augmente avec chaque ligne (triés dans l'ordre croissant de WithdrawDate
) - ainsi que chaque ligne, une quantité toujours croissante est soustraite de TotalAmount
, dessin Balance
plus proche de 0.
La requête ci-dessus vous donnera l'équilibre de chaque ligne mais pas le statut. Pour obtenir le statut, vous devrez référencer la valeur Balance
pour la comparer à 0 et sélectionner une chaîne d'état correspondante à revenir. Balance
est une colonne calculée et afin de pouvoir y référoir, vous devez nier la requête et la référence ci-dessus Balance
au niveau extérieur. La nidification pourrait être faite avec une table dérivée ou une expression de table commune (CTE). Cette requête utilise un 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
;
Bien sûr, si vous n'avez pas besoin de retourner la balance - uniquement pour le comparer à 0, la nidification n'est pas nécessaire et vous pouvez mettre la fonction d.TotalAmount - SUM(w.WithdrawAmount) OVER (ORDER BY w.WithdrawDate ASC)
expression directement dans le boîtier, remplaçant Balance
.