SELECT id, string_agg(year_range, ', ') AS year_ranges
FROM (
SELECT id, CASE WHEN count(*) > 1
THEN min(year)::text || '-' || max(year)::text
ELSE min(year)::text
END AS year_range
FROM (
SELECT *, row_number() OVER (ORDER BY id, year) - year AS grp
FROM (
SELECT id, unnest(years) AS year
FROM (VALUES (2::int, '{1999,2000,2010,2011,2012}'::int[])
,(3, '{1990,1991,2007}')
) AS tbl(id, years)
) sub1
) sub2
GROUP BY id, grp
ORDER BY id, min(year)
) sub3
GROUP BY id
ORDER BY id
Menghasilkan tepat hasil yang diinginkan.
Jika Anda berurusan dengan array varchar (varchar[]
, masukkan saja ke int[]
, sebelum Anda melanjutkan. Tampaknya dalam bentuk hukum yang sempurna untuk itu:
years::int[]
Ganti sub-pilihan dalam dengan nama tabel sumber Anda dalam kode produktif.
FROM (VALUES (2::int, '{1999,2000,2010,2011,2012}'::int[])
,(3, '{1990,1991,2007}')
) AS tbl(id, years)
->
FROM tbl
Karena kita berurusan dengan angka yang naik secara alami (tahun) kita dapat menggunakan jalan pintas untuk membentuk kelompok tahun berturut-turut (membentuk rentang). Saya kurangi tahun itu sendiri dari nomor baris (diurutkan berdasarkan tahun). Untuk tahun berturut-turut, nomor baris dan tahun bertambah satu dan menghasilkan grp
yang sama nomor. Jika tidak, rentang baru akan dimulai.
Selengkapnya tentang fungsi jendela dalam manual di sini dan di sini .
Fungsi plpgsql mungkin lebih cepat dalam kasus ini. Anda harus menguji. Contoh dalam jawaban terkait ini:
Jumlah urutan pengulangan / duplikat berturut-turut
ROW_NUMBER() menunjukkan nilai yang tidak terduga