Deskripsi Anda menghasilkan definisi tabel seperti ini:
CREATE TABLE tbl (
lap_id serial PRIMARY KEY
, lap_no int NOT NULL
, car_type enum NOT NULL
, race_id int NOT NULL -- REFERENCES ...
, UNIQUE(race_id, car_type, lap_no)
);
Solusi umum untuk kelas masalah ini
Untuk mendapatkan urutan terpanjang (1 hasil, terpanjang dari semua, pilih sewenang-wenang jika ada ikatan):
SELECT race_id, car_type, count(*) AS seq_len
FROM (
SELECT *, count(*) FILTER (WHERE step)
OVER (ORDER BY race_id, car_type, lap_no) AS grp
FROM (
SELECT *, (lag(lap_no) OVER (PARTITION BY race_id, car_type ORDER BY lap_no) + 1)
IS DISTINCT FROM lap_no AS step
FROM tbl
) x
) y
GROUP BY race_id, car_type, grp
ORDER BY seq_len DESC
LIMIT 1;
count(*) FILTER (WHERE step)
hanya dihitung TRUE
(= langkah ke grup berikutnya), yang menghasilkan angka baru untuk setiap grup baru.
Terkait pertanyaan tentang SO, satu jawaban yang menampilkan solusi prosedural dengan plpgsql :
Jika persyaratan teratas adalah kinerja, fungsi plpgsql biasanya lebih cepat dalam kasus khusus ini karena dapat menghitung hasilnya dalam pemindaian tunggal.
Lebih cepat untuk nomor berurutan
Kita dapat memanfaatkan fakta bahwa berturut - turutlap_no
menentukan urutan, untuk versi yang jauh lebih sederhana dan lebih cepat :
SELECT race_id, car_type, count(*) AS seq_len
FROM (
SELECT race_id, car_type
, row_number() OVER (PARTITION BY race_id, car_type ORDER BY lap_no) - lap_no AS grp
FROM tbl
) x
GROUP BY race_id, car_type, grp
ORDER BY seq_len DESC
LIMIT 1;
Putaran berturut-turut berakhir dengan hal yang sama grp
. Setiap putaran yang hilang menghasilkan lebih rendah grp
per partisi.
Ini bergantung pada (race_id, car_type, lap_no)
keberadaan UNIQUE NOT NULL
. Nilai NULL atau duplikat dapat mematahkan logika.
Diskusi tentang alternatif Jack yang lebih sederhana
Versi @ Jack secara efektif menghitung semua putaran (baris) di mana sebelumnya lap_no
dalam hal ini race_id
sama car_type
. Itu lebih sederhana dan lebih cepat dan benar - selama masing car_type
- masing hanya dapat memiliki satu urutan per race_id
.
Tetapi untuk tugas sesederhana itu kueri bisa lebih sederhana, belum. Ini akan mengikuti secara logis bahwa semua lap_no
per (car_type, race_id)
harus dalam urutan , dan kami hanya bisa menghitung putaran:
SELECT race_id, car_type, count(*) AS seq_len
FROM tbl
GROUP BY race_id, car_type
ORDER BY seq_len DESC
LIMIT 1;
Sebaliknya, jika seseorang car_type
dapat memiliki beberapa urutan terpisah per race_id (dan pertanyaannya tidak menentukan sebaliknya), versi Jack akan gagal.
Lebih cepat untuk jenis balapan / mobil tertentu
Sebagai balasan atas komentar / klarifikasi dalam pertanyaan: membatasi kueri ke yang diberikan (race_id, car_type)
akan membuatnya lebih cepat , tentu saja:
SELECT count(*) AS seq_len
FROM (
SELECT row_number() OVER (ORDER BY lap_no) - lap_no AS grp
FROM tbl
WHERE race_id = 1
AND car_type = 'red'
) x
GROUP BY grp
ORDER BY seq_len DESC
LIMIT 1;
db <> biola di sini
Old SQL Fiddle
Indeks
Kunci untuk kinerja terbaik adalah indeks pas (kecuali untuk solusi prosedural yang disebutkan bekerja dengan pemindaian sekuensial tunggal). Sebuah indeks multicolumn seperti ini berfungsi terbaik:
CREATE INDEX tbl_mult_idx ON tbl (race_id, car_type, lap_no);
Jika tabel Anda memiliki UNIQUE
kendala yang saya asumsikan di atas, itu diterapkan hanya dengan indeks (unik) ini secara internal, dan Anda tidak perlu membuat indeks lain.