ЦИКЛ математика по нескольким датам в таблице - PullRequest
1 голос
/ 21 мая 2009

У меня есть @variabletable, который просто определяется как EOMDate (datetime), DandA (float), Coupon (float), EarnedIncome (float)

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

То, что я пытаюсь сделать, это после заполнения таблицы, мне нужно вернуться и вычислить поле EarnedIncome, чтобы заполнить его. формула DandA для текущего месяца минус DandA для предыдущего месяца плюс купон. Где у меня возникли проблемы, как я могу сделать обновление? Таким образом, для 6/30 значение должно быть 4453,12 (2375-24640,63) + 26718,75

Я с радостью возьму дубинку по голове, чтобы решить эту проблему. Благодарю. Кроме того, работает под MS SQL2005, поэтому, если это возможно, можно использовать любое решение типа CTE ROW_OVER.

Ответы [ 5 ]

1 голос
/ 21 мая 2009

Определенно есть несколько способов сделать это. Вы найдете плюсы и минусы в зависимости от размера вашего набора данных и других факторов.

Вот моя рекомендация ...

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

Мне больше нравится второй метод, потому что он будет рассчитываться только при наличии записи за предыдущий месяц.

(добавьте следующее к приведенному выше сценарию, чтобы увидеть разницу)

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

Это все вопрос именно того, что вы хотите. Используйте запись непосредственно перед текущей записью (независимо от даты) или используйте ТОЛЬКО запись, которая находится за месяц до текущей записи.

Извините за формат ... Редактор ответов Stackoverflow.com и я не очень хорошо играем вместе.

: D

1 голос
/ 21 мая 2009

Вам необходимо использовать такой подзапрос, как этот:

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

И я использовал эту вспомогательную функцию

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 голосов
/ 21 мая 2009

Другой альтернативой является вычисление промежуточного итога при вставке ваших данных, и есть ограничение, гарантирующее, что ваш промежуточный итог верен:

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/23/denormalizing-to-enforce-business-rules-running-totals.aspx

0 голосов
/ 21 мая 2009

Вы можете использовать подзапрос для выполнения вычисления, единственная проблема - что вы делаете с первым месяцем, потому что нет предыдущего значения DandA. Здесь я установил 0, используя isnull. Запрос выглядит как

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

Это также предполагает, что у вас есть только одна запись в месяц в каждой таблице, и что между месяцами нет пробелов.

0 голосов
/ 21 мая 2009

Может быть способ сделать это с помощью одного оператора, но в подобных случаях я был бы склонен установить курсор для обхода каждой строки, вычисляя новое поле EarnedIncome для этой строки, обновляя строку , а затем перейдите к следующему ряду.

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 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...