1. ホーム
  2. sql

[解決済み] 日付範囲の比較

2022-08-07 12:12:02

質問

MySQL で、日付範囲 (範囲開始と範囲終了) のリストがある場合。

10/06/1983 to 14/06/1983
15/07/1983 to 16/07/1983
18/07/1983 to 18/07/1983

また、別の日付範囲がすでにリスト内の任意の範囲を含んでいるかどうかをチェックしたいのですが、どのようにすればよいでしょうか?

06/06/1983 to 18/06/1983 = IN LIST
10/06/1983 to 11/06/1983 = IN LIST
14/07/1983 to 14/07/1983 = NOT IN LIST

どのように解決するのですか?

これは古典的な問題で、実は論理を逆にすれば簡単なんです。

例を挙げましょう。

ここにある1つの期間と、何らかの形で重なる他の期間のさまざまなバリエーションを載せておきます。

           |-------------------|          compare to this one
               |---------|                contained within
           |----------|                   contained within, equal start
                   |-----------|          contained within, equal end
           |-------------------|          contained within, equal start+end
     |------------|                       not fully contained, overlaps start
                   |---------------|      not fully contained, overlaps end
     |-------------------------|          overlaps start, bigger
           |-----------------------|      overlaps end, bigger
     |------------------------------|     overlaps entire period

逆に、重ならないものを全部貼らせてください。

           |-------------------|          compare to this one
     |---|                                ends before
                                 |---|    starts after

ということで、単純に比較を減らすと

starts after end
ends before start

を実行すると、重なっていないものをすべて見つけ、次にマッチしていない期間をすべて見つけます。

最後のNOT IN LISTの例では、これらの2つのルールにマッチしていることがわかります。

次の期間が範囲内か範囲外かを決定する必要があります。

           |-------------|
   |-------|                       equal end with start of comparison period
                         |-----|   equal start with end of comparison period

テーブルに range_end と range_start というカラムがある場合、一致するすべての行を取得するための簡単な SQL を以下に示します。

SELECT *
FROM periods
WHERE NOT (range_start > @check_period_end
           OR range_end < @check_period_start)

このとき NOT が入っていることに注意してください。つの単純なルールは、すべての にマッチしない の行を見つけるので、単純なNOTはそれを逆にしてこう言います。 もしそれがマッチしない行の一つでないなら、マッチする行の一つでなければなりません。 .

ここで単純な反転の論理を適用してNOTを取り除くと、以下のようになります。

SELECT *
FROM periods
WHERE range_start <= @check_period_end
      AND range_end >= @check_period_start