在计算sql中使用前面的

时间:2016-03-03 06:09:14

标签: sql teradata

我需要使用B,C,D和B列来计算E列。前一行E ...我有样本陈述和计算供参考。请注意,prev(E)是我在计算中需要使用的E的前一个值,但我无法做到。

+---------------------------------------------------------------------------------------------------------------------------------------+  
| TransactionDt | total_allotment(B) | invchange(C) | roomssold_flag(D) | available(E) |       samplestatement            | calculation |   
+---------------------------------------------------------------------------------------------------------------------------------------+   
|    1/1/16     |         5          |      0       |       null        |       5      |  E=case when D=null then B       |  5          |   
|    1/2/16     |         5          |      0       |        1          |       4      |  E=case when C=0 then prev(E)-D  |  E=(5-1)    |   
|    1/3/16     |         5          |      0       |        0          |       4      |  E=case when C=0 then prev(E)-D  |  E=(4-0)    |   
|    1/4/16     |         6          |      1       |        1          |       5      |  E=case when C=1 then B-D        |  E=(6-1)    |   
|    1/5/16     |         6          |      0       |        0          |       5      |  E=case when C=0 then prev(E)-D  |  E=(5-0)    |   
|    1/6/16     |         7          |      1       |        1          |       6      |  E=case when C=1 then B-D        |  E=(7-1)    |   
+---------------------------------------------------------------------------------------------------------------------------------------+  

2 个答案:

答案 0 :(得分:1)

您可以使用带有前面子句的first_value()函数来获取私有值:

set dateformat dmy;
declare @t table (TransactionDt smalldatetime, b int, c int, d int, e int);
insert into @t (TransactionDt, b, c, d, e) values
(cast('01.01.2016' as date), 5, 0, null, 5),
(cast('02.01.2016' as date), 5, 0, 1, 4),
(cast('03.01.2016' as date), 5, 0, 0, 4),
(cast('04.01.2016' as date), 6, 1, 1, 5),
(cast('05.01.2016' as date), 6, 0, 0, 5),
(cast('06.01.2016' as date), 7, 1, 1, 6);

select
  t.*
  ,first_value(t.e) over(order by t.TransactionDt asc rows 1 preceding) [prevE]
  ,case t.c
     when 0 then
       first_value(t.e)
       over(order by t.TransactionDt asc rows 1 preceding)
       - t.d
     when 1 then
       t.b - t.d
   end [calculation]
from
  @t t
order by
  t.TransactionDt
;

在MS SQL 2012上测试。

我不是Teradata的忠实粉丝,但这应该有效:

select
  t.e
  ,sum(t.e) 
  over(order by t.TransactionDt asc rows between 1 preceding and 1 preceding) ePrev
  ,case t.c
     when 0 then
       sum(t.e) 
       over(order by t.TransactionDt asc rows between 1 preceding and 1 preceding)
       - t.d
     when 1 then
       t.b - t.d
   end calculation
from
  (
    select cast('01.01.2016' as date format 'dd.mm.yyyy') TransactionDt, 5 b, 0 c, null d, 5 e from (select 1 x) x
    union all
    select cast('02.01.2016' as date format 'dd.mm.yyyy') TransactionDt, 5 b, 0 c, 1 d, 4 e from (select 1 x) x
    union all
    select cast('03.01.2016' as date format 'dd.mm.yyyy'), 5, 0, 0, 4 from (select 1 x) x
    union all
    select cast('04.01.2016' as date format 'dd.mm.yyyy'), 6, 1, 1, 5 from (select 1 x) x
    union all
    select cast('05.01.2016' as date format 'dd.mm.yyyy'), 6, 0, 0, 5 from (select 1 x) x
    union all
    select cast('06.01.2016' as date format 'dd.mm.yyyy'), 7, 1, 1, 6 from (select 1 x) x
  ) t
order by
  t.TransactionDt
;

答案 1 :(得分:0)

当您需要在invchange=1时重新开始计算时,您必须使用

创建一个用于分区的组
sum(invchange)
over (order by TransactionDt
      rows unbounded preceding) as grp

invchange似乎基于前一行查询,因此您需要将其嵌套在Dervied Table中。

现在你的total_allotment值减去roomssold_flag的累积总和:

select t.*,
   b - sum(coalesce(D,0))
       over (partition by grp
             order by TransactionDt
             rows unbounded preceding)
from
 (
   select TransactionDt,b,c,d,
      sum(c) over (order by TransactionDt rows unbounded preceding) as grp
   from t
 ) as t

顺便说一句,使用0/1标志进行动态分区与RESET WHEN

类似