88

このテーブルは、セッション (イベント) を格納するために使用されます。

CREATE TABLE session (
  id int(11) NOT NULL AUTO_INCREMENT
, start_date date
, end_date date
);

INSERT INTO session
  (start_date, end_date)
VALUES
  ("2010-01-01", "2010-01-10")
, ("2010-01-20", "2010-01-30")
, ("2010-02-01", "2010-02-15")
;

範囲間で競合が発生することは望ましくありません。2010-01-05から2010-01-25
の新しいセッションを挿入する必要があるとしましょう。 競合するセッションを知りたいです。

これが私のクエリです:

SELECT *
FROM session
WHERE "2010-01-05" BETWEEN start_date AND end_date
   OR "2010-01-25" BETWEEN start_date AND end_date
   OR "2010-01-05" >= start_date AND "2010-01-25" <= end_date
;

結果は次のとおりです。

+----+------------+------------+
| id | start_date | end_date   |
+----+------------+------------+
|  1 | 2010-01-01 | 2010-01-10 |
|  2 | 2010-01-20 | 2010-01-30 |
+----+------------+------------+

それを取得するより良い方法はありますか?


フィドル

4

8 に答える 8

170

私はかつて書いたカレンダーアプリケーションでそのようなクエリをしました。私はこのようなものを使用したと思います:

... WHERE new_start < existing_end
      AND new_end   > existing_start;

更新これは間違いなく機能するはずです((ns、ne、es、ee)=(new_start、new_end、existing_start、existing_end)):

  1. ns --ne --es --ee:重複せず、一致しません(ne <esのため)
  2. ns --es --ne --ee:重複して一致
  3. es --ns --ee --ne:重複および一致
  4. es --ee --ns --ne:重複せず、一致しません(ns> eeのため)
  5. es --ns --ne --ee:重複して一致
  6. ns --es --ee --ne:重複および一致

これがフィドルです

于 2010-03-30T14:37:09.123 に答える
36
SELECT * FROM tbl WHERE
existing_start BETWEEN $newStart AND $newEnd OR 
existing_end BETWEEN $newStart AND $newEnd OR
$newStart BETWEEN existing_start AND existing_end

if (!empty($result))
throw new Exception('We have overlapping')

これらの 3 行の sql 句は、重複が必要な 4 つのケースをカバーしています。

于 2011-10-31T16:59:11.397 に答える
18

ラミーの答えは良いですが、もう少し最適化できます。

SELECT * FROM tbl WHERE
existing_start BETWEEN $newSTart AND $newEnd OR
$newStart BETWEEN existing_start AND existing_end

これにより、範囲が重複する 4 つのシナリオすべてが捕捉され、重複しない 2 つのシナリオが除外されます。

于 2013-02-18T19:55:09.363 に答える
4

(s1, e1) と (s2, e2) のような 2 つの間隔が与えられ、s1<e1 と s2<e2
の場合、次のようにオーバーラップを計算できます。

SELECT 
     s1, e1, s2, e2,
     ABS(e1-s1) as len1,
     ABS(e2-s2) as len2,
     GREATEST(LEAST(e1, e2) - GREATEST(s1, s2), 0)>0 as overlaps,
     GREATEST(LEAST(e1, e2) - GREATEST(s1, s2), 0) as overlap_length
FROM test_intervals 

1 つの間隔が他の間隔内にある場合にも機能します。

于 2016-01-16T08:03:05.633 に答える