LoginSignup
6
5

More than 5 years have passed since last update.

yancya には OVERLAPS がわからぬ

Last updated at Posted at 2014-07-11

概要

PostgreSQL に範囲型が来る前から overlaps という便利な演算子があったという事を最近知ったので調べてみたところ、謎の挙動があったので考察します。

-- 片方が1日だけだと true だが
  select ('2014-01-01'::date, '2014-01-01'::date)
overlaps ('2014-01-01'::date, '2014-01-31'::date);
-- t

-- 範囲が延びると false
  select ('2013-01-01'::date, '2014-01-01'::date)
overlaps ('2014-01-01'::date, '2014-01-31'::date);
-- f

なぜ範囲が1日か2日以上かで判定が変わってしまうのか...

議論

-- range の && だと全部 true
select daterange('2014-01-01'::date, '2014-01-01'::date, '[]') &&
       daterange('2014-01-01'::date, '2014-01-31'::date, '[]');
-- t
select daterange('2013-01-01'::date, '2014-01-01'::date, '[]') &&
       daterange('2014-01-01'::date, '2014-01-31'::date, '[]');
-- t

-- date の range で終端が開放の場合は全部 false 
select daterange('2014-01-01'::date, '2014-01-01'::date, '[)') &&
       daterange('2014-01-01'::date, '2014-01-31'::date, '[)');
-- f
select daterange('2013-01-01'::date, '2014-01-01'::date, '[)') &&
       daterange('2014-01-01'::date, '2014-01-31'::date, '[)');
-- f

-- timestamp の range で終端が開放の場合も全部 false 
select tsrange('2014-01-01'::timestamp, '2014-01-01'::timestamp, '[)') &&
       tsrange('2014-01-01'::timestamp, '2014-01-31'::timestamp, '[)');
-- f
select tsrange('2013-01-01'::timestamp, '2014-01-01'::timestamp, '[)') &&
       tsrange('2014-01-01'::timestamp, '2014-01-31'::timestamp, '[)');
-- f

-- between も範囲が1日だからといって判定が変わったりしない(そもそも '[]' だし)
select '2014-01-01'::timestamp between '2014-01-01' and '2014-01-01';
-- t
select '2014-01-01'::timestamp between '2013-01-01' and '2014-01-01';
-- t

うーん... 範囲だからというより、やはり overlaps だけ異端児な気がします...

追記

http://www.postgresql.jp/document/9.3/html/functions-datetime.html
最新のマニュアルで、この現象について言及されてました。
流石 PostgreSQL !ドキュメントが素晴らしい

この式は、2つの時間間隔が重なる(その終端で定義されます)時に真を返します。重ならない場合は偽を返します。終端は日付、時刻、タイムスタンプ、もしくは、日付/時刻/タイムスタンプに続く時間間隔で指定されます。値の組み合わせが与えられた際、開始と終了のいずれを先に記述しても構いません。OVERLAPSは与えられた値の内、若いものを開始として扱います。各時間間隔は、start <=time < endといった半開区間として見なされます。ただし、startとendが同じ値の場合には単一の時間点となります。これは、例えば終了点のみが同じである2つの時間間隔は、必ずしも重ならないことを意味します。

SELECT (DATE '2001-02-16', DATE '2001-12-21') OVERLAPS
       (DATE '2001-10-30', DATE '2002-10-30');
Result: true
SELECT (DATE '2001-02-16', INTERVAL '100 days') OVERLAPS
       (DATE '2001-10-30', DATE '2002-10-30');
Result: false
SELECT (DATE '2001-10-29', DATE '2001-10-30') OVERLAPS
       (DATE '2001-10-30', DATE '2001-10-31');
Result: false
SELECT (DATE '2001-10-30', DATE '2001-10-30') OVERLAPS
       (DATE '2001-10-30', DATE '2001-10-31');
Result: true

要するに (a, b) の場合は daterange(a, b, '[)') として扱うけど、(a, a) だったら daterange(a, a, '[]') として扱うからねって事だと思います。
えー。

6
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5