2009-05-21 7 views
1

J'ai un @variabletable simplement défini comme EOMDate (datetime), DandA (float), Coupon (float), EarnedIncome (float)mathématiques tsql sur plusieurs dates dans une table

04/30/2008, 20187.5,17812.5,NULL 
05/31/2008, 24640.63, 22265.63, NULL 
06/30/2008, 2375, 26718.75,NULL 

Ce que je suis en train de faire est après que la table est remplie, j'ai besoin de revenir en arrière et de calculer le champ EarnedIncome pour le peupler. la formule est DandA pour le mois en cours moins DandA pour le mois précédent plus coupon. Là où j'ai des problèmes, comment puis-je faire la mise à jour? Donc, pour 6/30 la valeur devrait être 4453.12 (2375-24640.63) +26718.75

Je serai heureux de prendre un clubbing sur la tête pour obtenir ce résolu. Merci. En outre, s'exécutant sous MS SQL2005, toute solution de type COW ROW_OVER peut être utilisée si possible.

Répondre

1

Vous devez utiliser une sous-requête comme ceci:

UPDATE @variabletable v1 
SET EarnedIncome = DandA 
- (SELECT DandA FROM @variabletable v2 WHERE GetMonthOnly(DATEADD(mm, -1, v2.EOMDate)=GetMonthOnly(v1.EOMDate)) 
+ Coupon 

Et je faisais usage de cette fonction d'assistance

DROP FUNCTION GetMonthOnly 
GO 
CREATE FUNCTION GetMonthOnly 
(
    @InputDate DATETIME 
) 
RETURNS DATETIME 
BEGIN 
    RETURN CAST(CAST(YEAR(@InputDate) AS VARCHAR(4)) + '/' + 
       CAST(MONTH(@InputDate) AS VARCHAR(2)) + '/01' AS DATETIME) 
END 
GO 
+0

avait déjà une fonction de la date equlivant mais cette réponse m'a fait pointé dans la bonne direction, merci! –

-1

Il peut y avoir un moyen de le faire en une seule déclaration, mais dans des cas comme celui-ci, je serais enclin à configurer un curseur pour parcourir chaque ligne, en calculant le nouveau champ EarnedIncome pour cette ligne, mettre à jour la ligne, puis passer à la ligne suivante.

Ex:

DECLARE @EOMDateVal DATETIME 
DECLARE @EarnedIncomeVal FLOAT 

DECLARE updCursor CURSOR FOR 
    SELECT EOMDate FROM @variabletable 

OPEN updCursor 

FETCH NEXT FROM updCursor INTO @EOMDateVal 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    // Compute @EarnedIncomeVal for this row here. 
    // This also gives you a chance to catch data integrity problems 
    // that would cause you to fail the whole batch if you compute 
    // everything in a subquery. 

    UPDATE @variabletable SET EarnedIncome = @EarnedIncomeVal 
     WHERE EOMDate = @EOMDateVal 

    FETCH NEXT FROM updCursor INTO @EOMDateVal 
END 
CLOSE updCursor 
DEALLOCATE updCursor 
0

Vous pouvez utiliser une sous-requête pour effectuer la calcuation, le seul problème est que faites-vous avec le premier mois parce qu'il n'y a pas de valeur DandA précédente. Ici, je l'ai mis à 0 en utilisant isnull. La requête ressemble

Update MyTable 
Set EarnedIncome = DandA + Coupon - IsNull( Select Top 1 DandA 
              From MyTable2 
              Where MyTable.EOMDate > MyTable2.EOMDate 
              Order by MyTable2.EOMDate desc), 0) 

Cela suppose aussi que vous avez seulement un enregistrement par mois dans chaque tableau, et qu'il y are't tout écart entre les mois.

1

Il y a certainement assez peu de moyens de le faire. Vous trouverez des avantages et des inconvénients en fonction de la taille de votre ensemble de données et d'autres facteurs.

Voilà ma recommandation ...

Declare @table as table 
(
    EOMDate DateTime, 
    DandA float, 
    Coupon Float, 
    EarnedIncome Float 
) 

Insert into @table Values('04/30/2008', 20187.5,17812.5,NULL) 
Insert into @table Values('05/31/2008', 24640.63, 22265.63, NULL) 
Insert into @table Values('06/30/2008', 2375, 26718.75,NULL) 


--If we know that EOMDate will only contain one entry per month, and there's *always* one entry a month... 
Update @Table Set 
EarnedIncome=DandA- 
(Select top 1 DandA 
from @table t2 
where t2.EOMDate<T1.EOMDate 
order by EOMDate Desc)+Coupon 
From @table T1 
Select * from @table 

--If there's a chance that there could be more per month, or we only want the values from the previous month (do nothing if it doesn't exist) 

Update @Table Set 
EarnedIncome=DAndA-(
Select top 1 DandA 
From @table T2 
Where DateDiff(month, T1.EOMDate, T2.EOMDate)=-1 
Order by EOMDate Desc)+Coupon 
From @Table T1 

Select * from @table 
--Leave the null, it's good for the data (since technically you cannot calculate it without a prior month). 

J'aime la deuxième meilleure méthode car il ne calcule s'il existe un record pour le mois précédent.

(ajoutez ce qui suit au script ci-dessus pour voir la différence)

--Add one for August 
Insert into @table Values('08/30/2008', 2242, 22138.62,NULL) 


Update @Table Set 
EarnedIncome=DAndA-(
     Select top 1 DandA 
     From @table T2 
     Where DateDiff(month, T1.EOMDate, T2.EOMDate)=-1 
     Order by EOMDate Desc 
)+Coupon 
From @Table T1 

--August is Null because there's no july 
Select * from @table 

Il est une question exactement ce que vous voulez. Utilisez l'enregistrement traitant directement l'enregistrement en cours (quelle que soit la date), ou utilisez UNIQUEMENT l'enregistrement qui est un mois avant l'enregistrement en cours.

Désolé pour le format ... Stackoverflow.com éditeur de réponse et je ne joue pas bien ensemble.

: D

Questions connexes