このテーブルはセッション(イベント)を保存するために使用されます:
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 |
+----+------------+------------+
それを取得するより良い方法はありますか?
かつて書いたカレンダーアプリケーションでこのようなクエリがありました。私はこのようなものを使用したと思います:
... WHERE new_start < existing_end
AND new_end > existing_start;
[〜#〜] update [〜#〜]これは間違いなく動作するはずです((ns、ne、es、ee)=(new_start、new_end、existing_start 、existing_end)):
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')
Sql句のこれらの3行は、必要な重複の4つのケースをカバーしています。
Lamyの答えは良いのですが、もう少し最適化できます。
SELECT * FROM tbl WHERE
existing_start BETWEEN $newSTart AND $newEnd OR
$newStart BETWEEN existing_start AND existing_end
これにより、範囲が重複する4つのシナリオすべてがキャッチされ、重複しない2つのシナリオは除外されます。
私は同様の問題に直面していました。私の問題は、ブロックされた日付の範囲で予約を停止することでした。たとえば、5月2日から5月7日までの施設の予約はブロックされます。予約を検出して停止するには、重複する日付を見つける必要がありました。私のソリューションは、LordJavacに似ています。
SELECT * FROM ib_master_blocked_dates WHERE venue_id=$venue_id AND
(
(mbd_from_date BETWEEN '$from_date' AND '$to_date')
OR
(mbd_to_date BETWEEN '$from_date' AND '$to_date')
OR
('$from_date' BETWEEN mbd_from_date AND mbd_to_date)
OR
('$to_date' BETWEEN mbd_from_date AND mbd_to_date)
)
*mbd=master_blocked_dates
うまくいかない場合は教えてください。
(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つの簡単なステップで終了するようになりました(これは良いアプローチまたはメモリ消費ではないかもしれません)-
SELECT * FROM duty_register WHERE employee = '2' AND (
(
duty_start_date BETWEEN {$start_date} AND {$end_date}
OR
duty_end_date BETWEEN {$start_date} AND {$end_date}
)
OR
(
{$start_date} BETWEEN duty_start_date AND duty_end_date
OR
{$end_date} BETWEEN duty_start_date AND duty_end_date)
);
これにより、重複する日付範囲を持つエントリを見つけることができました。
これが誰かを助けることを願っています。