2015-12-07 3 views
0

У меня есть функция, get_untracked_moves, ниже. Моя цель состоит в том, чтобы для всех данных между двумя диапазонами дат находить последовательные события, которые находятся дальше, чем p_separation_distance.PL/pgSQL: Сравнение последовательных строк

т.д .:

Если событие 1 и событие 2 40 м друг от друга, когда p_separation_distance 100й, запись будет возвращена с событием 1 ассоциированной cont_name как source_name и События 2 в cont_name как target_name.

CREATE FUNCTION get_untracked_moves(IN p_since_date TIMESTAMP WITHOUT TIME ZONE, IN p_before_date TIMESTAMP WITHOUT TIME ZONE, IN p_separation_distance INTEGER) 
    RETURNS TABLE (id INTEGER, 
      asset_name CHARACTER VARYING, 
      source_name CHARACTER VARYING, 
      target_name CHARACTER VARYING, 
      source_time TIMESTAMP WITHOUT TIME ZONE, 
      target_time TIMESTAMP WITHOUT TIME ZONE,    
      source_lat DOUBLE PRECISION, 
      source_lon DOUBLE PRECISION,    
      target_lat DOUBLE PRECISION, 
      target_lon DOUBLE PRECISION) AS $$ 

    DECLARE  
     d_previous_location GEOMETRY; 
     d_previous_name CHARACTER VARYING; 
     d_previous_time TIMESTAMP WITHOUT TIME ZONE; 

     d_cur record; 
    BEGIN 
     -- Begin @ 0,0 
     d_previous_location := st_setsrid(st_makepoint(0,0), 4326); 
     d_previous_name := ''; 
     d_previous_time := NULL; 

     FOR d_cur 
     IN 
      SELECT 
       rank() OVER (PARTITION BY events.asset_id ORDER BY events.event_time) AS idx, 
       tags.id asset_id, 
       tags.name asset_name, 
       d_previous_name, 
       conts.name cont_name, 
       events.position, 
       events.event_time evt_time 

      FROM 
       events 
      JOIN 
       assets tags ON tags.id = events.asset_id 
      JOIN 
       assets conts ON conts.id = events.container_asset_id 
      WHERE 
       events.event_time >= p_since_date 
      AND 
       events.event_time <= p_before_date 
     LOOP 
       IF (d_previous_time = NULL) THEN 
        d_previous_time := events.event_time; 
       END IF; 

       IF (st_distancesphere(events.position, d_previous_location)>=p_separation_distance) THEN 
        RETURN NEXT; 
       END IF; 

       d_previous_location := events.position; 
       d_previous_name := conts.name; 
       d_previous_time := events.event_time; 

     END LOOP; 
    END; 
    $$ 
LANGUAGE plpgsql VOLATILE; 

Функция создает отлично, но когда я иду, чтобы запустить его с:

select * from get_untracked_moves('2015-11-1', '2015-12-1', 10000); 

я получаю:

ERROR: missing FROM-clause entry for table "events" 
LINE 1: SELECT (st_distancesphere(events.position, d_previous_locati... 
           ^
QUERY: SELECT (st_distancesphere(events.position, d_previous_location)>=p_separation_distance) 
CONTEXT: PL/pgSQL function "get_untracked_moves" line 41 at IF 

********** Error ********** 

ERROR: missing FROM-clause entry for table "events" 
SQL state: 42P01 
Context: PL/pgSQL function "get_untracked_moves" line 41 at IF 

Что я здесь отсутствует? Я думал, что включение FROM events в мое заявление SELECT было достаточно.

+1

Вы должны читать на 'LAG()' функции окна и сделать все это в SQL ... –

+0

Спасибо за предложение! Я бы очень хотел это сделать, но plpgsql; есть еще одна логика, которую я удалил, пытаясь сделать это как можно меньше, чтобы воспроизвести. – FuriousFolder

+0

'событий' не существует внутри цикла. Обратитесь к этому столбцу как 'd_cur.position' –

ответ

2

Каждому проходу цикла присваивается значение записи, содержащей соответствующую строку набора результатов выбора. Таким образом, events не виден внутри цикла. Вместо этого используйте d_cur.position, чтобы обратиться к этой колонке.

BTW, как прокомментировал ваш вопрос, вы действительно должны использовать функцию окна lag и избавиться от беспорядочного цикла.

Как предложение проверить этот вопрос:

select idx, asset_id, asset_name, previous_name, cont_name, position, evt_time 
from (
    select 
     rank() over (partition by e.asset_id order by e.event_time) as idx, 
     st_distancesphere(
      e.position, 
      lag(e.position, 1, e.position) over (order by e.event_time) 
     ) >= p_separation_distance as b, 
     t.id as asset_id, 
     t.name as asset_name, 
     lag(c.name, 1) as previous_name, 
     c.name as cont_name, 
     e.position, 
     e.event_time as evt_time 
    from 
     events e 
     inner join 
     assets tags on t.id = e.asset_id 
     inner join 
     assets c on c.id = e.container_asset_id 
    where 
     e.event_time >= p_since_date 
     and 
     e.event_time <= p_before_date 
) s 
where b 
Смежные вопросы