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
正確に生成します 望ましい結果。
varcharの配列を処理する場合(varchar[]
、int[]
にキャストするだけです 、続行する前に。そのためには完全に合法的な形式のようです:
years::int[]
内側の副選択を、生産的なコードのソーステーブルの名前に置き換えます。
FROM (VALUES (2::int, '{1999,2000,2010,2011,2012}'::int[])
,(3, '{1990,1991,2007}')
) AS tbl(id, years)
->
FROM tbl
自然に昇順の数字を扱っているので (年)ショートカットを使用して、連続する年のグループを形成できます(範囲を形成します)。行番号(年順)から年自体を減算します。連続する年については、行番号と年の両方が1ずつ増加し、同じgrp
を生成します。 番号。それ以外の場合は、新しい範囲が始まります。
ウィンドウ関数の詳細 マニュアルの
この場合、plpgsql関数はさらに高速になる可能性があります。テストする必要があります。これらの関連する回答の例:
連続した繰り返し/重複の順序付けられた数
ROW_NUMBER()に予期しない値が表示される