Membangun tabel ini (tidak menggunakan kata kunci "tanggal" SQL sebagai nama kolom.):
CREATE TABLE tbl(
pid int
, the_date date
, PRIMARY KEY (pid, the_date)
);
Pertanyaan:
SELECT pid, the_date
, row_number() OVER (PARTITION BY pid, grp ORDER BY the_date) AS in_streak
FROM (
SELECT *
, the_date - '2000-01-01'::date
- row_number() OVER (PARTITION BY pid ORDER BY the_date) AS grp
FROM tbl
) sub
ORDER BY pid, the_date;
Mengurangi date
dari date
lain menghasilkan integer
. Karena Anda mencari hari berturut-turut, setiap baris berikutnya akan lebih besar satu . Jika kita kurangi row_number()
dari itu, seluruh beruntun berakhir di grup yang sama (grp
) per pid
. Maka mudah untuk membagikan nomor per grup.
grp
dihitung dengan dua pengurangan, yang harus tercepat. Alternatif yang sama cepatnya adalah:
the_date - row_number() OVER (PARTITION BY pid ORDER BY the_date) * interval '1d' AS grp
Satu perkalian, satu pengurangan. Penggabungan string dan casting lebih mahal. Uji dengan EXPLAIN ANALYZE
.
Jangan lupa untuk mempartisi dengan pid
tambahan di keduanya langkah, atau Anda akan secara tidak sengaja mencampur grup yang harus dipisahkan.
Menggunakan subkueri, karena biasanya lebih cepat daripada CTE . Tidak ada yang tidak bisa dilakukan oleh subquery biasa.
Dan karena Anda menyebutkannya:dense_rank()
jelas tidak diperlukan di sini. Dasar row_number()
melakukan pekerjaannya.