4

I'd like to detect changes in column values in this (example) db

    WITH events(id, row,event) AS (
    VALUES
    (1,1, 0 )
   ,(1,2, 0 ) 
   ,(1,3, 1 )
   ,(1,4, 0 )
   ,(1,5, 1 )
   ,(2,1, 0 )
   ,(2,2, 1 )
   ,(3,1, 0 )
   ,(3,2, 0 )
   )
   select * from events

What I am looking for is code for a new column 'code' which switches to 1 AFTER de event column shows a 1. Within the same id the code stays 1. For this example this new column wil look like this

    WITH events2(id, row,event, code) AS (
    VALUES
    (1,1, 0, 0 )
   ,(1,2, 0, 0 ) 
   ,(1,3, 1, 0 )
   ,(1,4, 0, 1 ) -- notice the switch here
   ,(1,5, 1, 1 ) -- 
   ,(2,1, 0, 0 )
   ,(2,2, 1, 0 )
   ,(3,1, 0, 0 )
   ,(3,2, 0, 0 )
   )
   select * from events2

I have a hunch that the answer will be related to the answer on this question : PostgreSQL window function: partition by comparison

Somehow I cannot figure this out myself..

Peter

1 Answer 1

0

COALESCE over a scalar subquery:

WITH events(id, zrow, zevent) AS (
    VALUES
    (1,1, 0 ) ,(1,2, 0 ) ,(1,3, 1 ) ,(1,4, 0 ) ,(1,5, 1 )
   ,(2,1, 0 ) ,(2,2, 1 )
   ,(3,1, 0 ) ,(3,2, 0 )
   )
SELECT id, zrow, zevent
        , COALESCE((SELECT 1 FROM events ex WHERE ex.id = ev.id AND ex.zrow < ev.zrow AND ex.zevent> 0),0) AS oevent
 FROM events ev
        ;

Or, avoid the COALESCE() by typecasting the boolean EXISTS() to INTEGER:

WITH events(id, zrow,event) AS (
    VALUES
    (1,1, 0 ) ,(1,2, 0 ) ,(1,3, 1 ) ,(1,4, 0 ) ,(1,5, 1 )
   ,(2,1, 0 ) ,(2,2, 1 )
   ,(3,1, 0 ) ,(3,2, 0 )
   )
SELECT id, zrow, event
        , EXISTS(SELECT 1 FROM events ex WHERE ex.id = ev.id AND ex.zrow < ev.zrow AND ex.event> 0)::integer AS oevent
FROM events ev
        ;

Find the MAX() value over the previous records within the same group (frame):

WITH events(id, zrow,event) AS (
    VALUES
    (1,1, 0 ) ,(1,2, 0 ) ,(1,3, 1 ) ,(1,4, 0 ) ,(1,5, 1 )
   ,(2,1, 0 ) ,(2,2, 1 )
   ,(3,1, 0 ) ,(3,2, 0 )
   )
, drag AS (
        SELECT id, zrow, event, MAX(event)
                OVER (PARTITION BY id
                        ORDER BY zrow
                        ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
                        ) AS lagged
        FROM events ev
        )
SELECT id, zrow, event
        , COALESCE(lagged,0) AS oevent
        FROM drag dr
        ;

The same without the extra CTE:

WITH events(id, zrow,event) AS (
    VALUES
    (1,1, 0 ) ,(1,2, 0 ) ,(1,3, 1 ) ,(1,4, 0 ) ,(1,5, 1 )
   ,(2,1, 0 ) ,(2,2, 1 )
   ,(3,1, 0 ) ,(3,2, 0 )
   )
SELECT id, zrow, event, COALESCE(MAX(event) OVER (PARTITION BY id
                                                ORDER BY zrow
                                                ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
                                ),0) AS lagged
        FROM events ev
        ;

Another way to perform the self-join would be to use a recursive query.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.