MySQL में डेट रेंज के ओवरलैप की जाँच करें


82

इस तालिका का उपयोग सत्रों (घटनाओं) को संग्रहीत करने के लिए किया जाता है:

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 |
+----+------------+------------+

वहाँ एक बेहतर तरीका है कि मिल रहा है?


बेला


1
आपकी तीसरी शर्त गलत है। माना जाता है "2010-01-05" <= start_date AND "2010-01-25" >= end_date। दृश्य के लिए stackoverflow.com/a/28802972/632951 देखें । आपकी वर्तमान तीसरी स्थिति कभी भी मूल्यांकन नहीं करेगी, क्योंकि पहली (और दूसरी) स्थिति पहले से ही इसे कवर करती है।
पचेरियर

जवाबों:


156

मैंने एक कैलेंडर एप्लिकेशन के साथ ऐसी क्वेरी की थी जिसे मैंने एक बार लिखा था। मुझे लगता है कि मैंने कुछ इस तरह इस्तेमाल किया:

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

अद्यतन यह निश्चित रूप से काम करना चाहिए ((ns, ne, es, ee) = (new_start, new_end, current_start, current_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: ओवरलैप और मैच

यहाँ एक बेला है


7
महान काम करता है!, लेकिन मुझे लगता है कि @Pierre de LESPINAY अपनी क्वेरी में समावेशी श्रेणियों की तलाश कर रहा है: जहाँ new_start <= मौजूदा_एंड और new_end> = मौजूदा_स्टार्ट;
ओस्वाल्डो मर्कैडो

16
@OvaldoM अगर वह वास्तव में थे, तो उन्होंने लगभग 2 साल पहले शिकायत की होगी ...
आत्मा

मैं एक घटना आज समाप्त करता हूं और दूसरा आज शुरू होता है, क्या वे ओवरलैप करते हैं? मेरी राय में, वे ओवरलैप करेंगे। लेकिन SQL क्वेरी यह नहीं कहेगी: sqlfiddle.com/# .2
AL

2
@soulmerge, वास्तव में, उन्होंने =इसके बारे में शिकायत करने के लिए परेशान करने के बजाय सिर्फ अपने वास्तविक कोड में जोड़ा होगा।
पचेरियर

32
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 मामलों को कवर करती हैं।


7
भले ही ओपी स्पष्ट रूप से इस अतिव्यापी परिभाषा की तलाश नहीं कर रहा था, लेकिन यह उत्तर प्रश्न नाम से वर्णित समस्या का सबसे अच्छा समाधान है। मैं इस ओवरलैप की तलाश में था, जो सही ओवरलैप है।
Cec

2
मुझे यकीन नहीं है कि आप "सही ओवरलैप" से क्या मतलब है लेकिन @soulmerge द्वारा शीर्ष उत्तर लैमी के इस जवाब के बराबर है। : मैं साबित करने के लिए तुल्यता जेड 3 प्रमेय सॉल्वर का उपयोग करने में सक्षम था grantjenks.com/projects/equivalent-inequalities
GrantJ

16

लैमी का जवाब अच्छा है, लेकिन आप इसे थोड़ा और अनुकूलित कर सकते हैं।

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

यह उन सभी चार परिदृश्‍यों को पकड़ लेगा जहां रेंज ओवरलैप करते हैं और उन दो को बाहर करते हैं जहां वे नहीं हैं।


क्या इसके अलावा अन्य समाधान हैं और अन्य दो ऊपर हैं?
पचेरियर

4

मैंने भी इसी तरह की समस्या का सामना किया था। मेरी समस्या अवरुद्ध तारीखों के बीच बुकिंग बंद करने की थी। उदाहरण के लिए बुकिंग 2 से 7 वीं मई के बीच की संपत्ति के लिए अवरुद्ध है। मुझे बुकिंग का पता लगाने और रोकने के लिए किसी भी तरह की ओवरलैपिंग की तारीख की जरूरत थी। मेरा समाधान लॉर्डजैक के समान है।

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

मुझे पता है अगर यह काम नहीं करता है।


2

S1 <e1 और s2 <e2 के साथ दो अंतराल जैसे (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 

अगर एक अंतराल दूसरे के भीतर है तो भी काम करेगा।


0

हाल ही में मैं एक ही मुद्दे के साथ संघर्ष कर रहा था और इस एक आसान कदम के साथ समाप्त हुआ (यह एक अच्छा तरीका या मेमोरी खपत नहीं हो सकता है) -

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)
);

इसने मुझे ओवरलैपिंग डेट रेंज वाली प्रविष्टियाँ खोजने में मदद की।

आशा है कि यह किसी की मदद करता है।


0

डेटाबेस में डेट करने पर भी आप सभी डेट ओवरलैपिंग के मामलों को कवर कर सकते हैं:

SELECT * FROM `tableName` t
WHERE t.`startDate` <= $toDate
AND (t.`endDate` IS NULL OR t.`endDate` >= $startDate);

यह वैसे भी नए प्रारंभ / समाप्ति तिथियों के साथ ओवरलैप होने वाले सभी रिकॉर्ड लौटाएगा।


0

मैकराकेन का जवाब एक प्रदर्शन के नजरिए से बेहतर है क्योंकि दो तारीखों के ओवरलैप होने पर मूल्यांकन के लिए उसे कई OR की आवश्यकता नहीं होती है। अच्छा समाधान!

हालाँकि मैंने पाया कि MySQL में आपको माइनस ऑपरेटर के बजाय DatedIFF का उपयोग करना होगा -

SELECT o.orderStart, o.orderEnd, s.startDate, s.endDate
, GREATEST(LEAST(orderEnd, endDate) - GREATEST(orderStart, startDate), 0)>0 as overlaps
, DATEDIFF(LEAST(orderEnd, endDate), GREATEST(orderStart, startDate)) as overlap_length
FROM orders o
JOIN dates s USING (customerId)
WHERE 1
AND DATEDIFF(LEAST(orderEnd, endDate),GREATEST(orderStart, startDate)) > 0;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.