2つの日付の間に一連の日付を生成したいとします。関数 generate_series
のみ提供
Function Argument Type Return Type Description
generate_series(start, stop, step interval) timestamp or timestamp with time zone setof timestamp or setof timestamp with time zone (same as argument type) Generate a series of values, from start to stop with a step size of step
だから私はこれをどうやってやりますか?
これには_generate_series
_を使用できますが、必ず引数を「タイムゾーンなしのタイムスタンプ」に明示的にキャストしてください。そうしないと、デフォルトで「タイムゾーン付きのタイムスタンプ」。 PostgreSQLは、両方の入力に対して_generate_series
_をオーバーロードします。
timestamp with timezone
_の問題ここで欠点を確認できます。
_SET timezone = 'America/Santiago';
SELECT generate_series(date '2016-08-15', date '2016-08-15', '1 day');
SELECT generate_series(date '2016-08-14', date '2016-08-15', '1 day');
_
上記のどちらも同じ日数を返します。ここでもう一度見ることができます。
_SET timezone = 'America/Sao_Paulo';
SELECT generate_series(date '2016-10-16', date '2016-10-17', '1 day');
SELECT generate_series(date '2016-10-17', date '2016-10-17', '1 day');
_
上記は、1日の2つの範囲を示しています。
この動作の理由は、これらのタイムゾーンの「DST境界が、小時間のより適切な時間ではなく、真夜中にある」ことです。
では、「正しく行う」とはどのようなものですか、
_SELECT generate_series(
timestamp without time zone '2016-10-16',
timestamp without time zone '2016-10-17',
'1 day'
);
_
今すぐキャストできます。
_SELECT d::date
FROM generate_series(
timestamp without time zone '2016-10-16',
timestamp without time zone '2016-10-17',
'1 day'
) AS gs(d);
_
この質問と回答は、IRC(irc://irc.freenode.net/#postgresql)でのRhodiumToadとの会話に触発されました。彼は私をこの問題に変えましたソリューションを提供しました。
generate_series(date,date,interval)
遊んでみたところ、generate_series(date,date,interval)
をオーバーロードすることで、明示的に_timestamp without time zone
_にキャストする必要を省くことができることに気づきました
これが私の機能です
_CREATE FUNCTION generate_series( t1 date, t2 date, i interval )
RETURNS setof date
AS $$
SELECT d::date
FROM generate_series(
t1::timestamp without time zone,
t2::timestamp without time zone,
i
)
AS gs(d)
$$
LANGUAGE sql
IMMUTABLE;
_
これで、上記のテストケースを再実行できるようになりました。この2つはどちらも同じものを返します。
_SET timezone = 'America/Santiago';
SELECT d::date
FROM generate_series(date '2016-08-15', date '2016-08-15', '1 day')
AS gs(d);
SELECT d::date
FROM generate_series(
timestamp without time zone '2016-08-15',
timestamp without time zone '2016-08-15',
'1 day'
)
AS gs(d);
_
これら2つと同様に、
_SELECT d::date
FROM generate_series(date '2016-08-14', date '2016-08-15', '1 day')
AS gs(d);
SELECT d::date
FROM generate_series(
timestamp without time zone '2016-08-14',
timestamp without time zone '2016-08-15',
'1 day'
)
AS gs(d);
_
generate_series(date,date,int)
別のオプションは、新しい関数generate_series(date,date,int)
を作成することです ここで述べた理由により、両方を持つことはできません 。これらの1つを選んで、
_generate_series(date,date,interval)
generate_series(date,date,int)
_
2番目のオプションが必要な場合は、次の方法を試してください。
_CREATE FUNCTION generate_series( t1 date, t2 date, i int )
RETURNS setof date
AS $$
SELECT d::date
FROM generate_series(
t1::timestamp without time zone,
t2::timestamp without time zone,
i * interval '1 day'
)
AS gs(d)
$$
LANGUAGE sql
IMMUTABLE;
_
Ircのレビューで、これらのアイデアにはいくつかの問題があります。
<johto>
generate_series(date, date, unknown)
はすでに機能しています。 intバージョン(generate_series(date, date, '1 day')
など)で完全に壊さない場合は、戻り値の型をtimestamptzからdateに変更します。 _(date, date, interval)
_の場合、壊れるケースは少なくなりますが、出力タイプは変更します。 (また、現在「正常に機能」している_(date, date, '1 hour')
_で何が起こるかは明らかではありません)