tsql数学跨表中的多个日期

时间:2009-05-21 14:20:56

标签: tsql

我有一个@variabletable,简单定义为EOMDate(日期时间),DandA(浮动),优惠券(浮动),EarnedIncome(浮动)

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 个答案:

答案 0 :(得分:1)

您需要使用这样的子查询:

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

答案 1 :(得分:1)

肯定有很多方法可以做到这一点。您可以根据数据集的大小和其他因素找到优缺点。

这是我的推荐......

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

答案 2 :(得分:0)

您可以使用子查询来执行计算,唯一的问题是您对第一个月做了什么,因为之前没有DandA值。在这里,我使用isnull将其设置为0。查询看起来像

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

这也假设每张表每月只有一条记录,并且月份之间没有任何差距。

答案 3 :(得分:0)

另一种方法是在插入数据时计算运行总计,并且有一个约束保证您的运行总数是正确的:

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

答案 4 :(得分:-1)

可能有一种方法可以在一个语句中执行此操作,但在这种情况下,我倾向于设置游标遍历每一行,计算该行的新EarnedIncome字段,更新行,然后转到下一行。

例如:

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