123

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
4

10 に答える 10

465

これは古典的な問題であり、論理を逆にすると実際には簡単になります。

例を挙げましょう。

ここにある期間と、何らかの形で重複する他の期間のさまざまなバリエーションをすべて掲載します。

           |-------------------|          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に注意してください。2 つの単純なルールはすべての一致しない行を検出するため、単純な NOT はそれを逆にして、次のように言います

ここで単純な反転ロジックを適用して NOT を取り除くと、次のようになります。

SELECT *
FROM periods
WHERE range_start <= @check_period_end
      AND range_end >= @check_period_start
于 2008-09-27T12:38:15.530 に答える
8

1983 年 6 月 6 日から 1983 年 6 月 18 日までの例の範囲を取り、範囲にstartendという列があると仮定すると、次のような句を使用できます。

where ('1983-06-06' <= end) and ('1983-06-18' >= start)

つまり、テスト範囲の開始がデータベース範囲の終了前にあり、テスト範囲の終了がデータベース範囲の開始時または後であることを確認してください。

于 2008-09-27T12:41:20.593 に答える
5

RDBMSがOVERLAP()関数をサポートしている場合、これは簡単になります。自家製のソリューションは必要ありません。(Oracleでは、明らかに機能しますが、文書化されていません)。

于 2008-09-28T19:56:13.130 に答える
0
CREATE FUNCTION overlap_date(s DATE, e DATE, a DATE, b DATE)
RETURNS BOOLEAN DETERMINISTIC
RETURN s BETWEEN a AND b or e BETWEEN a and b or  a BETWEEN s and e;
于 2013-01-14T03:16:44.727 に答える
0

MySQLでこの問題に対処する関数を作成しました。使用する前に日付を秒に変換するだけです。

DELIMITER ;;

CREATE FUNCTION overlap_interval(x INT,y INT,a INT,b INT)
RETURNS INTEGER DETERMINISTIC
BEGIN
DECLARE
    overlap_amount INTEGER;
    IF (((x <= a) AND (a < y)) OR ((x < b) AND (b <= y)) OR (a < x AND y < b)) THEN
        IF (x < a) THEN
            IF (y < b) THEN
                SET overlap_amount = y - a;
            ELSE
                SET overlap_amount = b - a;
            END IF;
        ELSE
            IF (y < b) THEN
                SET overlap_amount = y - x;
            ELSE
                SET overlap_amount = b - x;
            END IF;
        END IF;
    ELSE
        SET overlap_amount = 0;
    END IF;
    RETURN overlap_amount;
END ;;

DELIMITER ;
于 2011-05-03T03:24:04.330 に答える
0

あなたの期待される結果であなたは言う

1983 年 6 月 6 日から 1983 年 6 月 18 日 = リスト内

ただし、この期間は、期間のテーブル (リストではありません!) のいずれの期間にも含まれていません。ただし、1983 年 10 月 6 日から 1983 年 6 月 14 日までの期間は重複しています。

Snodgrass の本 ( http://www.cs.arizona.edu/people/rts/tdbbook.pdf ) が役に立つかもしれません: これは mysql よりも前のものですが、時間の概念は変わっていません ;-)

于 2008-09-29T13:47:03.650 に答える
0

次の例を見てください。それはあなたのために役立ちます。

    SELECT  DISTINCT RelatedTo,CAST(NotificationContent as nvarchar(max)) as NotificationContent,
                ID,
                Url,
                NotificationPrefix,
                NotificationDate
                FROM NotificationMaster as nfm
                inner join NotificationSettingsSubscriptionLog as nfl on nfm.NotificationDate between nfl.LastSubscribedDate and isnull(nfl.LastUnSubscribedDate,GETDATE())
  where ID not in(SELECT NotificationID from removednotificationsmaster where Userid=@userid) and  nfl.UserId = @userid and nfl.RelatedSettingColumn = RelatedTo
于 2011-12-19T05:52:27.797 に答える
0

BETWEEN sql ステートメントを使用した別の方法

収録期間:

SELECT *
FROM periods
WHERE @check_period_start BETWEEN range_start AND range_end
  AND @check_period_end BETWEEN range_start AND range_end

除外期間:

SELECT *
FROM periods
WHERE (@check_period_start NOT BETWEEN range_start AND range_end
  OR @check_period_end NOT BETWEEN range_start AND range_end)
于 2015-10-15T12:35:22.517 に答える