在PL / SQL中,如何根据下一行更新行?

时间:2010-11-11 15:29:11

标签: sql oracle ora-00934

我正在使用Oracle PL / SQL。

我有一个带时间戳的表T,如果它们按列B和时间戳排序,我希望将列A的行设置为与前一行的值相同,前提是时间戳没有不同超过45秒。

在伪代码中,它类似于:

UPDATE T t_curr
  SET A =
    (SELECT A
      FROM T t_prev
      INNER JOIN t_curr
        ON (t_prev is the row right before t_curr, when you sort by B and Timestamp)
          AND t_curr.Timestamp - t_prev.Timestamp < 45
    )

我试过了:

UPDATE T t_curr
  SET A =
    (SELECT A
      FROM T t_prev
      INNER JOIN t_curr
        ON RANK (t_curr)
          OVER (B, Timestamp)
          = 1 + RANK (t_prev)
          OVER (B, Timestmap)
          AND t_curr.Timestamp - t_prev.Timestamp < 45
    )

但我得到了:

  

错误(38,16):PL / SQL:ORA-00934:此处不允许使用组功能

指向RANK的第一个实例。

我做错了什么,我该如何做到这一点?

5 个答案:

答案 0 :(得分:3)

尝试使用合并声明。不确定它是否完全符合你的要求,但它应该有效。不幸的是,insert子句是必要的)但不应该被调用。

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)

答案 1 :(得分:1)

你可以尝试这样的事情:

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

答案 2 :(得分:1)

另一种选择......并没有完全做到想要的东西,因为它忽略了对B进行排序的要求,但它可能会给你一些思考....没有表定义和事情,它有点难以准确掌握所需的内容。

编辑:再次阅读问题,看起来你的语法错了。组功能(超前/滞后/等级等)只能出现在选择列表或order by子句中。它们在连接之后进行评估,其中包括group by和having子句。所以下面显示的内容应该有效。

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)

答案 3 :(得分:0)

你可以尝试(可能需要一些调整来使它正确,但这个想法是由偏移的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
                      )
                  )

答案 4 :(得分:0)

你能做的是。

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

这要求您要更新的列为空,除非您要更新所有列。