तुलना करने की तिथि सीमा


116

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

जवाबों:


439

यह एक शास्त्रीय समस्या है, और यह वास्तव में आसान है यदि आप तर्क को उलटते हैं।

मैं आपको एक उदाहरण देता हूं।

मैं एक समय की अवधि यहाँ पोस्ट करूँगा, और अन्य अवधियों के सभी विभिन्न रूपांतर जो किसी तरह से ओवरलैप होंगे।

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

फिर आप उन सभी को खोज लेंगे जो ओवरलैप नहीं करते हैं, और फिर आप सभी गैर-मिलान अवधि पाएंगे।

अपने अंतिम नॉट लिस्ट उदाहरण के लिए, आप देख सकते हैं कि यह उन दो नियमों से मेल खाता है।

आपको यह तय करने की आवश्यकता होगी कि निम्नलिखित अवधि क्या है?

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

यदि आपकी तालिका में रेंज_एंड और रेंज_स्टार्ट नामक कॉलम हैं, तो सभी मिलान पंक्तियों को पुनः प्राप्त करने के लिए यहां कुछ सरल एसक्यूएल है:

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

वहाँ नोट नहीं । चूंकि दो सरल नियम सभी गैर-मिलान पंक्तियों को ढूंढते हैं, एक साधारण यह कहने के लिए इसे उल्टा नहीं करेगा: यदि यह गैर-मिलान पंक्तियों में से एक नहीं है, तो इसे मिलान वाले में से एक होना चाहिए

यहाँ से छुटकारा पाने के लिए सरल उलटा तर्क लागू करना और आप इसे समाप्त कर देंगे:

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

45
उत्तर के लिए हमें "ACII आरेख" ध्वज की आवश्यकता है जो आपको एक से अधिक बार उत्थान करने की अनुमति देता है
जॉनी बुकानन

29
शायद 5 सबसे अच्छे उत्तरों में से एक मैंने एसओ पर देखा है। समस्या की शानदार व्याख्या, समाधान का अच्छा चलना, और ... चित्र!
डेविद्रव

10
अगर मैं इसे एक से अधिक बार वोट कर सकता हूं, तो मैं करूंगा। एक सामान्य मुद्दे के महान, स्पष्ट और संक्षिप्त विवरण, जो एक समाधान है, जिसके बारे में मैंने शायद ही कभी इतनी अच्छी तरह से व्याख्या की हो!
कोनोरप

2
बहुत बढ़िया जवाब! केवल एक चीज जो मैं जोड़ूंगा - यह तय करने के संदर्भ में कि क्या समापन बिंदु शामिल हैं या नहीं - सब कुछ क्लीनर से बाहर काम करता है यदि आप एक तरफ बंद अंतराल के साथ जाते हैं और दूसरे पर एक खुला अंतराल। जैसे किसी श्रेणी की शुरुआत बिंदु में शामिल होती है, और सीमा का अंत नहीं होता है। खासकर जब आप तारीखों के संयोजन, और विभिन्न प्रस्तावों के समय के साथ काम कर रहे हैं, तो सब कुछ सरल हो जाता है।
ग्रहण

1
अच्छा उत्तर। इसे एलन के अंतराल बीजगणित के रूप में भी वर्णित किया गया है । मेरे पास एक समान उत्तर है और एक टिप्पणीकार के साथ कितने अलग-अलग तुलना करने पर भयंकर लड़ाई हुई है।
जोनाथन लेफ्लर

8

अपनी उदाहरण सीमा 06/06/1983 से 18/06/1983 तक ले जाना और यह मान लेना कि आपके पास अपनी श्रेणियों के लिए आरंभ और अंत नामक कॉलम हैं, आप इस तरह एक क्लॉज का उपयोग कर सकते हैं

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

यानी जाँच करें कि आपकी टेस्ट रेंज की शुरुआत डेटाबेस रेंज के अंत से पहले है, और आपकी टेस्ट रेंज का अंत डेटाबेस रेंज के शुरू होने पर या उसके बाद है।


4

यदि आपका RDBMS OVERLAP () फ़ंक्शन का समर्थन करता है तो यह तुच्छ हो जाता है - होमग्रोन समाधानों की कोई आवश्यकता नहीं है। (ओरेकल में यह उचित रूप से काम करता है लेकिन अनिर्दिष्ट है)।


1
महाकाव्य समाधान। ठीक काम करता है। यह ओरेकल में 2 तिथि सीमाओं (s1, e1) और (s2, e2) के लिए वाक्यविन्यास है: दोहरे से 1 का चयन करें जहां (s1, e1) ओवरलैप्स (s2, e2);
इहेबीह

0

आपके अपेक्षित परिणामों में आप कहते हैं

06/06/1983 से 18/06/1983 = सूची में

हालाँकि, यह अवधि सम्‍मिलित नहीं है और न ही आपकी सारणी में किसी भी समयावधि द्वारा सम्‍मिलित है (न कि सूची!)। हालाँकि, यह 10/06/1983 से 14/06/1983 की अवधि को ओवरलैप करता है।

आप स्नोडग्रास पुस्तक ( http://www.cs.arizona.edu/people/rts/tdbbook.pdf ) उपयोगी पा सकते हैं : यह mysql को पूर्व-दिनांकित करता है लेकिन समय की अवधारणा परिवर्तित नहीं हुई है; ;-)


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 ;

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

0

MS SQL पर इसे आज़माएं


WITH date_range (calc_date) AS (
SELECT DATEADD(DAY, DATEDIFF(DAY, 0, [ending date]) - DATEDIFF(DAY, [start date], [ending date]), 0)
UNION ALL SELECT DATEADD(DAY, 1, calc_date)
FROM date_range 
WHERE DATEADD(DAY, 1, calc_date) <= [ending date])
SELECT  P.[fieldstartdate], P.[fieldenddate]
FROM date_range R JOIN [yourBaseTable] P on Convert(date, R.calc_date) BETWEEN convert(date, P.[fieldstartdate]) and convert(date, P.[fieldenddate]) 
GROUP BY  P.[fieldstartdate],  P.[fieldenddate];


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)

-2
SELECT * 
FROM tabla a 
WHERE ( @Fini <= a.dFechaFin AND @Ffin >= a.dFechaIni )
  AND ( (@Fini >= a.dFechaIni AND @Ffin <= a.dFechaFin) OR (@Fini >= a.dFechaIni AND @Ffin >= a.dFechaFin) OR (a.dFechaIni>=@Fini AND a.dFechaFin <=@Ffin) OR
(a.dFechaIni>=@Fini AND a.dFechaFin >=@Ffin) )

ढेर अतिप्रवाह में आपका स्वागत है! इस कोड स्निपेट के लिए धन्यवाद, जो कुछ तत्काल सहायता प्रदान कर सकता है। एक उचित व्याख्या यह दर्शाती है कि यह समस्या का एक अच्छा समाधान क्यों है, यह दिखाते हुए इसके शैक्षिक मूल्य में बहुत सुधार करेगा , और यह भविष्य के पाठकों के लिए समान के साथ अधिक उपयोगी होगा, लेकिन समान नहीं, प्रश्न। कृपया स्पष्टीकरण जोड़ने के लिए अपने उत्तर को संपादित करें, और इस बात का संकेत दें कि क्या सीमाएँ और मान्यताएँ लागू होती हैं।
टोबी स्पाइट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.