Veljko
Veljko

Reputation: 1808

SQL - find two consecutive rows for the same ID

We have table like this:

ID  PERSON  GROUP  ASSIGNEDGROUP  CHANGEDATE
1   null    GROUP1 GROUP1         01.01.2014
1   NAME1   null   GROUP1         02.01.2014
1   null    GROUP2 GROUP2         03.01.2014
2   null    GROUP1 GROUP1         04.01.2014
2   NAME1   null   GROUP1         05.01.2014
2   null    GROUP2 GROUP2         06.01.2014
2   null    GROUP3 GROUP3         07.01.2014

We would like to find two consecutive rows where PERSON field will have value null for the same ID and based on the date field. (if PERSON field is null then GROUP field has value and vice verse)

So for this example only last two rows should be listed because they are for the same ID and dates between them are consecutive

2   null    GROUP2 GROUP2         06.01.2014
2   null    GROUP3 GROUP3         07.01.2014

I am trying to write some SQL syntax but really do not know how to start, this probably is some complex expression. I suppose first thing to do is to get two consecutive rows based on dates and on them to check if PERSON is null.

Thank you in advance

Upvotes: 1

Views: 988

Answers (1)

Gordon Linoff
Gordon Linoff

Reputation: 1271023

This is a good place to use lag() and lead():

select t.*
from (select t.*,
             lag(person) over (partition by id order by changedate) as person_prev,
             lead(person) over (partition by id order by changedate) as person_next
      from table t
     ) t
where person is null and
      (person_prev is null or person_next is null);

EDIT:

The above doesn't quite work because NULL will be returned for the first or last row for each id. Ooops. Here is one fix:

select t.*
from (select t.*,
             lag(person) over (partition by id order by changedate) as person_prev,
             lead(person) over (partition by id order by changedate) as person_next,
             lag(id) over (partition by id order by changedate) as id_prev,
             lead(id) over (partition by id order by changedate) as id_next
      from table t
     ) t
where person is null and
      ((person_prev is null and id_prev is not null) or
       (person_next is null and id_next is not null)
      );

EDIT II;

How about looking for two groups that are not-null?

select t.*
from (select t.*,
             lag(group) over (partition by id order by changedate) as group_prev,
             lead(group) over (partition by id order by changedate) as group_next
      from table t
     ) t
where group is not null and
      (group_prev is not null or group_next is not null);

Note: group is a very bad name for a column, because it is a SQL reserved word.

Upvotes: 2

Related Questions