user1635134
user1635134

Reputation: 23

Get a query to list the records that are on and in between the start and the end values of a particular column for the same Id

There is a table with the columns :

USE 'table';  
insert into person values   
('11','xxx','1976-05-10','p1'),  
('11','xxx ','1976-06-11','p1'),  
('11','xxx ','1976-07-21','p2'),  
('11','xxx ','1976-08-31','p2'),  

Can anyone suggest me a query to get the start and the end date of the person with respect to the place he changed chronologically.

The query I wrote

SELECT PId,Name,min(Start_Date) as sdt, max(Start_Date) as edt, place 
from ** 
group by Place;

only gives me the first two rows of my answer. Can anyone suggest the query??

Upvotes: 1

Views: 152

Answers (2)

MvG
MvG

Reputation: 60958

This isn't pretty, and performance might be horrible, but at least it works:

select min(sdt), edt, place
from (
  select A.Start_Date sdt, max(B.Start_Date) edt, A.place
  from person A
       inner join person B on A.place = B.place
                          and A.Start_Date <= B.Start_Date
       left join person C on A.place != C.place
                         and A.Start_Date < C.Start_Date
                         and C.Start_Date < B.Start_Date
  where C.place is null
  group by A.Start_Date, A.place
) X
group by edt, place

The idea is that A and B represent all pairs of rows. C will be any row in between these two which has a different place. So after the C.place is null restriction, we know that A and B belong to the same range, i.e. a group of rows for one place with no other place in between them in chronological order. From all these pairs, we want to identify those with maximal range, those which encompass all others. We do so using two nested group by queries. The inner one will choose the maximal end date for every possible start date, whereas the outer one will choose the minimal start date for every possible end date. The result are maximal ranges of chronologically subsequent rows describing the same place.

Upvotes: 1

Omesh
Omesh

Reputation: 29111

This can be achived by:

SELECT Id, PId,
       MIN(Start_Date) AS sdt,
       MAX(Start_Date) as edt,
       IF(`place` <> @var_place_prev, (@var_rank:= @var_rank + 1), @var_rank) AS rank,
       (@var_place_prev := `place`) AS `place`
FROM person, (SELECT @var_rank := 0, @var_place_prev := "") dummy
GROUP BY rank, Place;

Example: SQLFiddle

If you want records to be ordered by ID then:

SELECT Id, PId,
       MIN(Start_Date) AS sdt,
       MAX(Start_Date) as edt,
       `place`
FROM(
     SELECT Id, PId,
            Start_Date
            IF(`place` <> @var_place_prev,(@var_rank:= @var_rank + 1),@var_rank) AS rank,
            (@var_place_prev := `place`) AS `place`
     FROM person, (SELECT @var_rank := 0, @var_place_prev := "") dummy
     ORDER BY ID ASC
    ) a
GROUP BY rank, Place;

Upvotes: 0

Related Questions