В този отговор ще приема, че полето „id“ номерира редовете последователно, когато са сортирани по нарастваща дата, както е в примерните данни. (Такава колона може да бъде създадена, ако не съществува).
Това е пример за техника, описана тук и тук .
1) Присъединете таблицата към себе си на съседни стойности на "id". Това сдвоява съседни редове. Изберете редове, където полето „разпределение“ е променено. Съхранявайте резултата във временна таблица, като също поддържате работещ индекс.
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;
Това ви дава таблица с „края на предишния период“, „началото на следващия период“ и „стойността на „разпределението“ в предишния период“ във всеки ред:
+------+------------+------------+------------+
| 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) Имаме нужда от началото и края на всеки период в един и същи ред, така че трябва да комбинираме съседни редове отново. Направете това, като създадете втора временна таблица като boundaries
но с idx
поле 1 по-голямо:
+------+------------+------------+
| 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 |
+------+------------+------------+
Сега се присъединете към idx
и получаваме отговора:
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 |
+------------+------------+------------+
** Обърнете внимание, че този отговор получава правилно "вътрешните" периоди, но пропуска двата "крайни" периода, където разпределението =0 в началото и разпределението =5 в края. Те могат да бъдат изтеглени чрез UNION
клаузи, но исках да представя основната идея без това усложнение.