PL / pgSQL:比较连续行

时间:2015-12-07 17:11:05

标签: postgresql plpgsql

我有下面的函数get_untracked_moves。我的目标是,对于两个日期范围之间的所有数据,找到比p_separation_distance更远的连续事件。

例如:

如果事件1和事件2相隔40米,当p_separation_distance为100米时,将返回一条记录,其中事件1的关联cont_name为source_name,事件2的cont_name为{ {1}}。

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就足够了。

1 个答案:

答案 0 :(得分: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