In PL/SQL, how do you update a row based on the next row?

后端 未结 5 1116
轮回少年
轮回少年 2021-01-18 10:20

I\'m using Oracle PL/SQL.

I have a timestamped table T, and I want to set a row\'s value for column A to be the same as that of the previous row, if they\'re sorted

相关标签:
5条回答
  • 2021-01-18 10:45

    Try using a merge statement. Not sure it quite does what you want but it should work. Unfortunately the insert clause is necessary) but shouldn't ever be called.

    merge into t a
    using (
      select 
        A, 
        B, 
        timestamp, 
        lag(A) over (order by id, timestamp) as prior_A,
        lag(timestamp) over (order by B, timestamp) as prior_timestamp
      from t) b
    on  (a.B = b.B)
    when matched then 
      update set a.a = case when b.timestamp-b.prior_timestamp <= 45 
        then b.prior_A else b.A end
    when not matched then insert (B) values (null)
    
    0 讨论(0)
  • 2021-01-18 10:50

    Can you try something like this:

    update x 
    set x = y.A
    from T x
    join T y
    where x.B = (select MAX(B) from T where B < y.B)
    and x.Timestamp = (select MAX(Timestamp) from T where Timestamp < y.Timestamp)
    and y.Timestamp - x.Timestamp < 45
    
    0 讨论(0)
  • 2021-01-18 10:59

    What you can do is.

    update t
    set colToUpdate = nextValue
    from  (
    select A
          ,B
          ,C
          ,(LEAD(B, 1, null) over (order by A)) as nextValue
      FROM db.schema.table
      ) as t
        where colToUpdate is null
    

    This requires that the column you want to update is null, unless you want to update all of them.

    0 讨论(0)
  • 2021-01-18 11:02

    And another option... doesn't quite do what do want because it ignores the requirement to sort on B but it might give you something to think about.... Without table definitions and things it was a little hard to get a handle on exactly what was required.

    Edit: on reading the question again, it looks like your syntax is wrong. Group functions (lead/lag/rank etc) can only appear in the select list or the order by clause. They are evaluated after the joins, where, group by and having clauses. So something like what is shown below should work.

    update T a
    set A = (select 
      new_A
      from (
      select 
        B, 
        A, 
        timestamp, 
        first_value(A) 
          over (order by timestamp range between 45 preceding and current row) as new_A
      from mike_temp_1
    ) b where b.id = a.id)
    
    0 讨论(0)
  • 2021-01-18 11:10

    You could try (might need some tweaking to get it right, but the idea is two identical ordered subqueries joined by offset rownumbers)

    update T set a = (select A1
                     from (
                           select S1.A A1, rownum r1
                           from (select * from T order by B, timestamp) S1
                           left outer join
                           select S2.A A2, rownum r2
                           from (select * from T order by B, timestamp) S2
                           on r1 = r2-1
                          )
                      )
    
    0 讨论(0)
提交回复
热议问题