Reputation: 23
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
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
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;
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