Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Membuat grup hari berturut-turut yang memenuhi kriteria tertentu

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.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tampilan INFORMATION_SCHEMA SQL Server | Lihat apakah Tabel Ada

  2. Mempertahankan integritas subclass dalam database relasional

  3. Bagaimana cara menanyakan kolom xml di tsql

  4. LIKE dan NULL dalam klausa WHERE dalam SQL

  5. Pilih database yang hanya berisi tabel tertentu