В PL / SQL, как вы обновляете строку на основе следующей строки? - PullRequest
5 голосов
/ 11 ноября 2010

Я использую Oracle PL / SQL.

У меня есть таблица меток времени T, и я хочу установить значение строки для столбца A таким же, как в предыдущей строке, если они отсортированы по столбцам B и Timestamp, при условии, что метки времени не отличаются более чем на 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 ]

3 голосов
/ 11 ноября 2010

Попробуйте использовать оператор слияния.Не уверен, что он делает то, что вы хотите, но это должно работать.К сожалению, предложение вставки необходимо), но никогда не должно вызываться.

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 голос
/ 11 ноября 2010

И еще один вариант ... не совсем делает то, что хочет, потому что игнорирует требование сортировки по B, но может дать вам кое-что для размышления .... Без определений таблиц и вещей было бы немного сложно получить точную информацию о том, что требовалось.

Редактировать: при повторном чтении вопроса, похоже, ваш синтаксис неправильный. Групповые функции (лидерство / отставание / ранг и т. Д.) Могут появляться только в списке выбора или в порядке сортировки. Они оцениваются после объединений, где, группируются и имеют пункты. Так что то, что показано ниже, должно работать.

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)
1 голос
/ 11 ноября 2010

Можете ли вы попробовать что-то вроде этого:

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 голосов
/ 11 января 2016

То, что вы можете сделать, это.

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

Это требует, чтобы столбец, который вы хотите обновить, был нулевым, если вы не хотите обновить все из них.

0 голосов
/ 11 ноября 2010

Вы можете попробовать (может потребоваться некоторая настройка, чтобы сделать это правильно, но идея состоит в том, чтобы два идентичных упорядоченных подзапроса соединились со смещенными рядами)

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
                      )
                  )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...