Jika kasus Anda sesederhana yang disarankan oleh nilai contoh, jawaban @Giorgos melayani dengan baik.
Namun, biasanya tidak demikian . Jika id
kolom adalah serial
, Anda tidak dapat mengandalkan asumsi bahwa baris dengan time
sebelumnya juga memiliki id
yang lebih kecil .
Juga, time
nilai (atau timestamp
seperti yang mungkin Anda miliki) dapat dengan mudah menjadi duplikat, Anda perlu membuat urutan pengurutan tidak ambigu.
Dengan asumsi keduanya bisa terjadi, dan Anda menginginkan id
dari baris dengan time
paling awal per irisan waktu (sebenarnya, yang terkecil id
untuk waktu paling awal , mungkin ada ikatan), kueri ini akan menangani situasi dengan benar:
SELECT *
FROM (
SELECT DISTINCT ON (way, grp)
id, way, time AS time_from
, max(time) OVER (PARTITION BY way, grp) AS time_to
FROM (
SELECT *
, row_number() OVER (ORDER BY time, id) -- id as tie breaker
- row_number() OVER (PARTITION BY way ORDER BY time, id) AS grp
FROM table1
) t
ORDER BY way, grp, time, id
) sub
ORDER BY time_from, id;
-
ORDER BY time, id
menjadi tidak ambigu. Dengan asumsi waktu tidak unik, tambahkan (diasumsikan unik)id
untuk menghindari hasil yang sewenang-wenang - yang dapat mengubah kueri dengan cara yang licik. -
max(time) OVER (PARTITION BY way, grp)
:tanpaORDER BY
, bingkai jendela mencakup semua baris PARTITION, jadi kita mendapatkan maksimum absolut per irisan waktu. -
Lapisan kueri luar hanya diperlukan untuk menghasilkan urutan pengurutan yang diinginkan dalam hasil, karena kita terikat pada
ORDER BY
yang berbeda di subkuerisub
dengan menggunakanDISTINCT ON
. Detail:
SQL Fiddle mendemonstrasikan kasus penggunaan.
Jika Anda ingin mengoptimalkan kinerja, fungsi plpgsql bisa lebih cepat dalam kasus seperti itu. Jawaban yang terkait erat:
Selain:jangan gunakan nama tipe dasar time
sebagai pengenal (juga kata yang dicadangkan dalam SQL standar ).