W tej odpowiedzi przyjmę, że pole „id” numeruje wiersze kolejno posortowane według rosnącej daty, tak jak to ma miejsce w przykładowych danych. (Taką kolumnę można utworzyć, jeśli nie istnieje).
To jest przykład techniki opisanej tutaj i tutaj .
1) Połącz tabelę ze sobą na sąsiednich wartościach „id”. Paruje sąsiednie rzędy. Wybierz wiersze, w których zmieniło się pole „alokacja”. Przechowuj wynik w tabeli tymczasowej, zachowując również bieżący indeks.
SET @idx = 0;
CREATE TEMPORARY TABLE boundaries
SELECT
(@idx := @idx + 1) AS idx,
a1.date AS prev_end,
a2.date AS next_start,
a1.allocation as allocation
FROM allocations a1
JOIN allocations a2
ON (a2.id = a1.id + 1)
WHERE a1.allocation != a2.allocation;
Daje to tabelę zawierającą „koniec poprzedniego okresu”, „początek następnego okresu” i „wartość „alokacji” w poprzednim okresie” w każdym wierszu:
+------+------------+------------+------------+
| idx | prev_end | next_start | allocation |
+------+------------+------------+------------+
| 1 | 2012-01-01 | 2012-01-02 | 0 |
| 2 | 2012-01-02 | 2012-01-03 | 2 |
| 3 | 2012-01-05 | 2012-01-06 | 0 |
+------+------------+------------+------------+
2) Potrzebujemy początku i końca każdego okresu w tym samym rzędzie, więc musimy ponownie połączyć sąsiednie rzędy. Zrób to, tworząc drugą tabelę tymczasową, taką jak boundaries
ale mając idx
pole 1 większe:
+------+------------+------------+
| idx | prev_end | next_start |
+------+------------+------------+
| 2 | 2012-01-01 | 2012-01-02 |
| 3 | 2012-01-02 | 2012-01-03 |
| 4 | 2012-01-05 | 2012-01-06 |
+------+------------+------------+
Teraz dołącz do idx
i otrzymujemy odpowiedź:
SELECT
boundaries2.next_start AS start,
boundaries.prev_end AS end,
allocation
FROM boundaries
JOIN boundaries2
USING(idx);
+------------+------------+------------+
| start | end | allocation |
+------------+------------+------------+
| 2012-01-02 | 2012-01-02 | 2 |
| 2012-01-03 | 2012-01-05 | 0 |
+------------+------------+------------+
** Zauważ, że ta odpowiedź poprawnie pobiera okresy „wewnętrzne”, ale pomija dwa okresy „krawędziowe”, gdzie alokacja =0 na początku i alokacja =5 na końcu. Można je pobrać za pomocą UNION
klauzul, ale chciałem przedstawić główny pomysł bez komplikacji.