Dalam jawaban ini, saya akan berasumsi bahwa bidang "id" memberi nomor pada baris secara berurutan ketika diurutkan berdasarkan tanggal yang bertambah, seperti pada contoh data. (Kolom seperti itu dapat dibuat jika tidak ada).
Ini adalah contoh teknik yang dijelaskan di sini dan di sini .
1) Gabungkan tabel ke dirinya sendiri pada nilai "id" yang berdekatan. Ini memasangkan baris yang berdekatan. Pilih baris di mana bidang "alokasi" telah berubah. Simpan hasilnya di tabel sementara, juga simpan indeks yang berjalan.
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;
Ini memberi Anda tabel yang memiliki "akhir periode sebelumnya", "awal periode berikutnya", dan "nilai 'alokasi' pada periode sebelumnya" di setiap baris:
+------+------------+------------+------------+
| 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) Kita membutuhkan awal dan akhir setiap periode di baris yang sama, jadi kita perlu menggabungkan baris yang berdekatan lagi. Lakukan ini dengan membuat tabel sementara kedua seperti boundaries
tetapi memiliki idx
bidang 1 lebih besar:
+------+------------+------------+
| 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 |
+------+------------+------------+
Sekarang gabung di idx
lapangan dan kami mendapatkan jawabannya:
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 |
+------------+------------+------------+
** Perhatikan bahwa jawaban ini mendapatkan periode "internal" dengan benar tetapi melewatkan dua periode "tepi" di mana alokasi =0 di awal dan alokasi =5 di akhir. Itu dapat ditarik menggunakan UNION
klausa tapi saya ingin menyajikan ide inti tanpa komplikasi itu.