在SQLServer2008中高效地编写此公式

在SQLServer2008中高效地编写此公式,sql,sql-server-2008,tsql,rdbms,Sql,Sql Server 2008,Tsql,Rdbms,假设我有一个表,这些是它的样本行 ChangeID Change 1 102 2 105 3 107 4 110 变化公式是 (CurrentRowChange - PreviousRowChange) / PreviousRowChange 因此: 对于第一行,它应该是0 第二排应为105-102/102 等等。如何用SQL高效地编写此公式 我知道我可以编写一个标量函数,然后执行RowNumber

假设我有一个表,这些是它的样本行

ChangeID    Change
   1         102
   2         105
   3         107
   4         110
变化公式是

(CurrentRowChange - PreviousRowChange) / PreviousRowChange
因此:

对于第一行,它应该是0 第二排应为105-102/102 等等。如何用SQL高效地编写此公式

我知道我可以编写一个标量函数,然后执行RowNumber和order By ChangeID,获取行号的更改值,然后找到当前行号-1,然后获取该行的更改值并进行除法


有没有更好的方法来实现这一点?

试一试,假设CHANGEID可以删除,并且是IDENTITY


试一试,假设CHANGEID可以删除并且是IDENTITY


虽然ChangeID在示例中是连续的,但我不认为它们总是连续的。所以我会这样做:

 with RankedIDs as
 select ChangeID
 , Change
 , rank() over
 (partition by ChangeID order by ChangeId) rank
 where something maybe ;

 select case
 when r1.rank = 1 then 0
 else (r1.change - r2.change) / r2.change
 end SomeName
 from RankedIds r1 join RankedIds r2 on r1.rank = r2.rank + 1

这是基本的想法。您可能需要添加除零保护

而ChangeID在示例中是连续的,我不认为它们总是连续的。所以我会这样做:

 with RankedIDs as
 select ChangeID
 , Change
 , rank() over
 (partition by ChangeID order by ChangeId) rank
 where something maybe ;

 select case
 when r1.rank = 1 then 0
 else (r1.change - r2.change) / r2.change
 end SomeName
 from RankedIds r1 join RankedIds r2 on r1.rank = r2.rank + 1
select T1.ChangeID,
       (1.0 * T1.Change / T2.Change) - 1 as Result
from TableName as T1
  outer apply (
              select top(1) T.Change
              from TableName as T
              where T.ChangeID < T1.ChangeID
              order by T.ChangeID desc
              ) as T2


这是基本的想法。您可能需要添加除零保护

我可以使用ChangeID作为自然数序列吗?@HamletHakobyan:当然可以。着手不需要做RowNumber。您的表达式可以简化为CurrentRowChange/PreviousRowChange-1我可以使用ChangeID作为自然数序列吗?@HamletHakobyan:当然可以。着手无需执行RowNumber。您的表达式可以简化为CurrentRowChange/PreviousRowChange-1Superb和simple:。杰出的只需要稍微调整一下。结果不正确。应为cur.Change-prev.Change/castprov.Change as floatRight,添加1.0*,该值应具有相同的结果。@DanBracuk:True,但问题的注释说ChangeID是一个自然数字序列,因此如果删除一行,这似乎是一个有效的假设。极好且简单:。杰出的只需要稍微调整一下。结果不正确。应为cur.Change-prev.Change/castprov.Change as floatRight,添加1.0*,该值应具有相同的结果。@DanBracuk:True,但问题的注释表明ChangeID是一个自然数序列,因此,这似乎是一个有效的假设,如果一行被删除,则不是。是的,我更喜欢这个解决方案,尽管Andomar更干净,因为这个解决方案处理的情况是,ChangeID可能不是连续的,并且PreviousRowChange可能与CurrentChangeID-1不一样。+1,但我会添加一个…/NULLIFb.change,0以防止被零除的错误。@Jack:Andomar的解决方案表明,您只需调用一个行号即可。您可以在连接条件中使用排名值,就像Andromar的解决方案使用ChangeId一样。@AndriyM我也同意Andromar的回答,如果ChangeId是按顺序的,否则该值将为零,示例是的,我更喜欢这个解决方案,尽管Andomar更干净,因为这个解决方案处理的情况是,ChangeID可能不是连续的,并且之前的行change可能与CurrentChangeID-1.+1不同,但我会添加一个…/NULLIFb.change,0以防止被零除的错误。@Jack:Andomar的解决方案表明,您只需调用一个行号即可。您可以在连接条件中使用排名值,就像Andomar的解决方案使用ChangeId一样。@AndriyM我也同意Andomar的回答,如果ChangeId是顺序的,否则该值将为零,例如
select T1.ChangeID,
       (1.0 * T1.Change / T2.Change) - 1 as Result
from TableName as T1
  outer apply (
              select top(1) T.Change
              from TableName as T
              where T.ChangeID < T1.ChangeID
              order by T.ChangeID desc
              ) as T2