Sql server 使用T-SQL中一行的上一个值计算值
我得到了下表,并希望在不使用游标或while循环的情况下,使用sql中前一行中相同列(Column2)的值来计算每一行上Column2的值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
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