TSQL-引用上一行中更改的值

时间:2018-11-16 07:54:30

标签: sql sql-server tsql sql-server-2012

我正在尝试进行行计算,以便将较大的值继续传送到后续行,直到比较较大的值为止。通过使用lag()函数将当前值与上一行进行比较来完成此操作。

代码

DECLARE @TAB TABLE (id varchar(1),d1 INT , d2 INT)

INSERT INTO @TAB (id,d1,d2) 

VALUES ('A',0,5)
      ,('A',1,2)
      ,('A',2,4) 
      ,('A',3,6)
      ,('B',0,4)
      ,('B',2,3)
      ,('B',3,2)
      ,('B',4,5)

SELECT id
      ,d1
      ,d2 = CASE WHEN id <> (LAG(id,1,0) OVER (ORDER BY id,d1)) THEN d2
                 WHEN d2 < (LAG(d2,1,0) OVER (ORDER BY id,d1)) THEN (LAG(d2,1,0) OVER (ORDER BY id,d1)) 
                 ELSE d2 END

输出(为清楚起见添加了od2行)

     +----+----+----+    +----+
     | id | d1 | d2 |    | od2|
     +----+----+----+    +----+
     | A  |  0 |  5 |    |  5 |
     | A  |  1 |  5 |    |  2 |
     | A  |  2 |  4 |    |  4 |
     | A  |  3 |  6 |    |  6 |
     | B  |  0 |  4 |    |  4 |
     | B  |  2 |  4 |    |  3 |
     | B  |  3 |  3 |    |  2 |
     | B  |  4 |  5 |    |  5 |
     +----+----+----+    +----+

从输出中可以看到,滞后函数引用的是上一行的原始值,而不是新值。反正有实现这一目标的方法吗?

所需的输出

     +----+----+----+    +----+
     | id | d1 | d2 |    | od2|
     +----+----+----+    +----+
     | A  |  0 |  5 |    |  5 |
     | A  |  1 |  5 |    |  2 |
     | A  |  2 |  5 |    |  4 |
     | A  |  3 |  6 |    |  6 |
     | B  |  0 |  4 |    |  4 |
     | B  |  2 |  4 |    |  3 |
     | B  |  3 |  4 |    |  2 |
     | B  |  4 |  5 |    |  5 |
     +----+----+----+    +----+

2 个答案:

答案 0 :(得分:2)

尝试一下:

SELECT id
      ,d1
      ,d2  
     ,MAX(d2) OVER (PARTITION BY ID ORDER BY d1)
FROM @TAB 

enter image description here

想法是使用MAX获取每个分区从开始到当前行的最大值。

答案 1 :(得分:0)

感谢您提供DDL脚本和DML。

一种方法是使用递归cte,如下所示。 1.首先根据id,d1和d2对所有记录进行排名。 -> CTE块 2.使用递归cte并使用rnk = 1获取第一个元素 3.字段“ compared_val”将检查前一个rnk中的值,以查看该值是否大于现有值,如果可以,则将交换该值

DECLARE @TAB TABLE (id varchar(1),d1 INT , d2 INT)

INSERT INTO @TAB (id,d1,d2) 

VALUES ('A',0,5)
      ,('A',1,2)
      ,('A',2,4) 
      ,('A',3,6)
      ,('B',0,4)
      ,('B',2,3)
      ,('B',3,2)
      ,('B',4,5)

;with cte
  as (select row_number() over(partition by id order by d1,d2) as rnk
            ,id,d1,d2     
        from @TAB    
      )
  ,data(rnk,id,d1,d2,compared_val)
    as (select rnk,id,d1,d2,d2 as compared_val
          from cte
         where rnk=1
         union all
        select a.rnk,a.id,a.d1,a.d2,case when b.compared_val > a.d2 then 
                                              b.compared_val 
                                         else a.d2
                                      end
          from cte a
          join data b
            on a.id=b.id
           and a.rnk=b.rnk+1
        )
select * from data order by id,d1,d2