Sql server 使用T-SQL中一行的上一个值计算值

Sql server 使用T-SQL中一行的上一个值计算值,sql-server,tsql,Sql Server,Tsql,我得到了下表,并希望在不使用游标或while循环的情况下,使用sql中前一行中相同列(Column2)的值来计算每一行上Column2的值 Id Date Column1 Column2 1 01/01/2011 5 5 => Same as Column1 2 02/01/2011 2 18 => (1 + (value of Column2 from the previous

我得到了下表,并希望在不使用游标或while循环的情况下,使用sql中前一行中相同列(Column2)的值来计算每一行上Column2的值

Id   Date             Column1    Column2
1    01/01/2011       5          5 => Same as Column1
2    02/01/2011       2          18 => (1 + (value of Column2 from the previous row)) * (1 + (Value of Column1 from the current row)) i.e. (1+5)*(1+2)
3    03/01/2011       3          76 => (1+18)*(1+3) = 19*4
and so on
有什么想法吗



假设至少有SQL Server 2005用于:


下面是一个使用ROW_NUMBER()的示例,如果Id不一定按顺序排列:

;with DataRaw as (
    select 1 as Id, '01/01/11' as Date, 5 as Column1 union
    select 2 as Id, '02/01/11' as Date, 2 as Column1 union
    select 4 as Id, '03/01/11' as Date, 3 as Column1
),
Data as (
    select RowId = ROW_NUMBER() over (order by Id), Id, Date, Column1 from DataRaw
),
Data2 as (
    select
        RowId, id, Date, Column1, Column1 as Column2
    from
        Data d
    where
        RowId = 1

    union all

    select
        d1.RowId, d1.id, d1.Date, d1.Column1, (1+d1.column1)*(1+d2.column2) as column2
    from
        Data d1
    cross join
        Data2 d2
    where
        d2.RowId + 1 = d1.RowId
)
select
    Id, Date, Column1, Column2
from
    Data2

编辑:我应该把这个问题读得更好

另一个办法是:

;with DataRaw as (
    select 1 as Id, '01/01/11' as Date, 5 as Column1 union
    select 2 as Id, '02/01/11' as Date, 2 as Column1 union
    select 4 as Id, '03/01/11' as Date, 3 as Column1
),
Data as (
    select Ord = ROW_NUMBER() over (order by Id), Id, Date, Column1 from DataRaw
),
select -- formula goes here, using current and prev as datasources.
from  data current
      left join data prev on current.Ord = prev.Ord + 1  -- pick the previous row by adding 1 to the ordinal
我认为正常连接到前一行要比CTE快。你;不过我得自己检查一下

对我来说更容易


祝你好运,GJ

我解决了刚才提到的问题

这是我的代码:

;with cteCalculation as (
    select t.Id, t.Column1, t.Column1 as Column2
        from table_1 t
        where t.Id = 1
    union all
    select t.Id, t.Column1, (1+t.Column1)*(1+c.Column2) as Column2
        from table_1 t
            inner join cteCalculation c
                on t.Id-1 = c.id
),
cte2 as(
select t.Id, t.Column1 as Column3
        from table_1 t
        where t.Id = 1
    union all
    select t.Id, (select column2+1 from cteCalculation c where c.id = t.id)  as Column3
        from table_1 t
            inner join cte2 c2
                on t.Id-1 = c2.id
)

select c.Id, c.Column1, c.Column2, c2.column3
    from cteCalculation c
inner join cte2 c2 on c.id = c2.id
结果如我所料:

1           5   5   5
2           2   18  19
3           3   76  77

只是好奇。我试图自己实现一个递归CTE,但想知道如果你不能假设Id是连续的,该怎么做?@mellamokb我想你可以用一个with CLUSE在(order by…)上做一行_num(),然后在递归CTE中引用它,但我不确定,这里没有SQL。您还可以查看lead()和lag()。其实你不知道;如果使用超前和滞后,则不需要CTE,它们也应该更快。@gjvdkamp:行数()的好主意!不幸的是,SQL Server没有超前和滞后。您好,很抱歉超前和滞后,在oracle上花了太多时间,它们在SQL上似乎不存在。我发布了我一直在研究的示例,并实现了您的ROW_NUMBER()想法。@GjdCamp:这将仅基于两个连续的行设置值。计算需要在整个数据集上累加,AFAIK只能通过递归CTE或类似光标的东西来完成,OP不想使用。进一步说明:您需要对d2.Column2的引用,以便使用前一条记录的值,该值不存在。查询需要如下所示:
选择d1.Ord,d1.Id,d1.Date,d1.Column1,(1+d1.Column1)*(1+d2.column2)作为数据d1中的column2左连接d1.Ord=d2.Ord+1上的数据d2,但是
d2.column2
来自哪里,因为基础表没有
column2
源列?好的,抱歉,我没有在原始帖子的代码视图中向右滚动。我们将表自身连接起来,然后我们将需要的两行数据(当前和以前)放在一起。那么你应该可以做计算了。我重命名别名来说明问题。不。无法从当前行和上一行计算列2。您需要将当前行和前面的所有行放在一起。在本例中,您也无法访问上一行的
列2
计算,因为两行的每一个组合都是独立于其他行一起进行的。请随意用SQL Server测试的一个工作示例来证明我的错误。啊,我明白了,不,我也不这么认为,CTE是解决问题的方法。如果你是问这个问题的人,请将这个答案标记为版主注意,以便合并你的帐户。
1           5   5   5
2           2   18  19
3           3   76  77