2009-05-21 5 views
1

Ich habe einen @variabletable einfach als EOMDate (Datumzeit) definiert sind, DandA (float), Coupon (float), EarnedIncome (float)Tsql Mathe über mehrere Tage, in einer Tabelle

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

Was ich versuche zu Nachdem die Tabelle ausgefüllt wurde, muss ich zurückgehen und das EarnedIncome-Feld berechnen, um es zu füllen. Die Formel ist DandA für den aktuellen Monat minus DandA für den vorherigen Monat plus Coupon. Wo habe ich Probleme, wie kann ich das Update machen? Also für 6/30 sollte der Wert 4453.12 (2375-24640.63) +26718.75

Ich werde gerne ein Clubbing über den Kopf nehmen, um dies gelöst zu bekommen. Vielen Dank. Unter MS SQL2005 kann auch jede Lösung vom Typ CTE ROW_OVER verwendet werden, wenn dies möglich ist.

Antwort

1

Sie würden eine Unterabfrage wie diese verwenden müssen:

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

Und ich war Verwendung dieser Hilfsfunktion

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

hatte bereits eine equlivant Funktion Datum, aber diese Antwort hat mich in die richtige Richtung, danke! –

-1

Es kann eine Art und Weise, dies zu tun in einer einzigen Aussage zu machen, Aber in solchen Fällen wäre ich geneigt, einen Cursor einzurichten, der jede Zeile durchläuft, das neue EarnedIncome-Feld für diese Zeile berechnet, die Zeile aktualisiert und dann zur nächsten Zeile geht.

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

Sie eine Unterabfrage die calcuation ausführen können, ist das einzige Problem, was Sie mit dem ersten Monat zu tun, weil es kein vorheriger DandA Wert ist. Hier habe ich es mit Isnull auf 0 gesetzt. Die Abfrage sieht aus wie

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

Dies setzt auch voraus, dass Sie nur in jeder Tabelle pro Monat einen Datensatz haben, und dass es are't Lücken zwischen den einzelnen Monaten.

1

Es ist auf jeden Fall ziemlich viele Möglichkeiten, dies zu tun. Abhängig von der Größe Ihres Datensatzes und anderen Faktoren finden Sie Vor- und Nachteile.

Hier ist meine Empfehlung ...

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). 

ich die zweite Methode am besten gefällt, weil es nur berechnen, wenn es einen Datensatz für den vorangegangenen Monat existiert.

(im folgenden auf die obige Skript fügen Sie den Unterschied zu sehen)

--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 

Es ist alles eine Frage der genau das, was Sie wünschen. Verwenden Sie den Datensatz, der den aktuellen Datensatz (unabhängig vom Datum) direkt verarbeitet, oder verwenden Sie NUR den Datensatz, der sich einen Monat vor dem aktuellen Datensatz befindet.

Sorry über das Format ... Stackoverflow.com Antwort Editor und ich nicht gut zusammen spielen.

: D

Verwandte Themen