अंतराल और द्वीप

Oct 16 2020

मेरे पास StartDate और EndDate के साथ एक तालिका है। मैं लापता तिथि प्राप्त करना चाहता था और स्क्रिप्ट मेरे पास है। लेकिन अगर यह डेटा दिया जाता है:

LocationID  StartDate   EndDate
----------  ----------  ----------  
1           2020-01-01  2020-01-03  
1           2020-01-04  2020-01-05  
1           2020-01-10  2020-01-15  

यह प्रश्न:

DECLARE @t table(PlaceID int, StartDate date, EndDate date);

INSERT @t(PlaceID, StartDate, EndDate) VALUES
(1,'20200101','20200103'),(1,'20200104','20200105'),(1,'20200110','20200115');

--(2,'20200103','20200106'),(2,'20200107','20200110'),(2,'20200120','20200123');

-- input parameters 
DECLARE @PlaceIDofInterest   int  = 1,
        @StartDateOfInterest date = '20200101', 
        @EndDateOfInterest   date = '20200131';
    
;WITH date_range(d) AS -- the entire range of days we care about
(
  SELECT @StartDateOfInterest UNION ALL
  SELECT DATEADD(DAY, 1, d) FROM date_range
         WHERE d < @EndDateOfInterest
),
islands AS -- grouped sets of days _not_ covered
(
  SELECT r.d, island = DATEADD(DAY, DENSE_RANK() OVER (ORDER BY r.d) * -1, r.d) 
    FROM date_range AS r
    LEFT OUTER JOIN @t AS t
      ON  r.d >= t.StartDate 
      AND r.d <= t.EndDate
      AND t.PlaceID = @PlaceIDofInterest
    WHERE t.PlaceID IS NULL
)
SELECT  
      MIN(d) as STARTDATE , 
      MAX(d) as ENDDATE-- for each island, grab the start and end
  FROM 
      islands 
 
  GROUP BY island 
  ORDER BY MIN(d);

यह आउटपुट लौटाता है:

STARTDATE   ENDDATE  
---------   ----------    
2020-01-06  2020-01-09  
2020-01-16  2020-01-31  

लेकिन मैं उत्पादन के रूप में चाहता था:

STARTDATE   ENDDATE
---------   ----------    
2020-01-03  2020-01-04  
2020-01-05  2020-01-10  
2020-01-15  2020-01-31  

मैं क्या बदलाव कर सकता हूं?

जोड़ने के लिए संपादित: रात से सुबह तक एक स्थान बुक किया जा सकता है। तो स्टार्ट नाइट को एंडेडेट मॉर्निंग। जब तक यह बुक नहीं हो जाता है, तब तक SOD लोकेशन रात को फ्री रहेगा। साथ ही स्‍टार्टडेट मॉर्निंग पर लोकेशन फ्री होगी।

1 जनवरी के 3 से 3 जनवरी को बुक किया जाता है - इसका मतलब है कि पहली रात से तीसरी सुबह तक। अगली बुकिंग केवल 4 रात को है। तो स्थान 3 रात से 4 सुबह तक भी मुफ्त है। तो मुझे परिणाम की आवश्यकता होगी 3 के रूप में एक प्रारंभ दिनांक और 4Jan एक पंक्ति में एंडडेट के रूप में। आशा है कि यह स्पष्ट है।

जवाब

1 nbk Oct 16 2020 at 20:57

आपको वास्तव में इसके लिए एक सीटी की आवश्यकता नहीं है

विंडो फ़ंक्शन LEAD वह कर सकता है जिसकी आपको आवश्यकता है

तारीखों के अनुरूप होने पर इसे परिष्कृत किया जा सकता है

CREATE table t1(PlaceID int, StartDate date, EndDate date);
GO
INSERT INTO  t1 (PlaceID, StartDate, EndDate) VALUES
(1,'20200101','20200103')
,(1,'20200104','20200111')
,(1,'20200111','20200113')
,(1,'20200114','20200121')
,(1,'20200121','20200123')
,(2,'20200103','20200106')
,(2,'20200107','20200110')
,(2,'20200120','20200123');
GO
SELECT
PlaceID
,EndDate
,Nextdate
FROM
(SELECT
PlaceID
,EndDate,
COALESCE(DATEADD(DAY,0,lead(StartDate,1,NULL)  OVER (partition by PlaceID ORDER BY StartDate)),EOMONTH(StartDate)) AS Nextdate
FROM t1) t2
WHERE EndDate != Nextdate
GO
प्लेसिड | एंडडेट | नेक्सटेट  
------: | : --------- | : ---------
      1 | 2020-01-03 | 2020-01-04
      1 | 2020-01-13 | 2020-01-14
      1 | 2020-01-23 | 2020-01-31
      2 | 2020-01-06 | 2020-01-07
      2 | 2020-01-10 | 2020-01-20
      2 | 2020-01-23 | 2020-01-31

db <> फिडल यहां

JonathanFite Oct 16 2020 at 21:06

@Nbk का उत्तर आपको वही मिलेगा जो आप चाहते हैं, मैं इसे यहां डाल रहा हूं क्योंकि यह आपके लिए दिलचस्प साबित हो सकता है; हालांकि यह पूरा नहीं है। फिलहाल, यह संभावित बुकिंग की तारीखों की सूची प्राप्त करता है और दिखाता है कि यह आपके द्वारा उल्लिखित नियमों के अनुसार बुक किया गया है या नहीं। यह एक कैलेंडर दृश्य या आपके लिए इसके जैसे कुछ के रूप में उपयोगी हो सकता है।

DECLARE @Source TABLE
    (
    LocationID INT NOT NULL
    , StartDate DATE NOT NULL
    , EndDate DATE NOT NULL
    )

INSERT INTO @Source 
    (LocationID, StartDate, EndDate)
VALUES (1, '1/1/2020', '1/3/2020')
    , (1, '1/4/2020', '1/5/2020')
    , (1, '1/10/2020', '1/15/2020')

DECLARE @LocationOfInterest INT = 1
DECLARE @StartDate DATE = '1/1/2020'
DECLARE @EndDate DATE = '1/31/2020'

;WITH CTE_I AS
    (
    SELECT *
        , PriorEndDate = LAG(EndDate) OVER (PARTITION BY LocationID ORDER BY StartDate)
        , NextStart = LEAD(StartDate) OVER (PARTITION BY LocationID ORDER BY StartDate)
    FROM @Source AS S
    WHERE LocationID = @LocationOfInterest
    )
, CTE_G AS
    (
    SELECT I.LocationID
        , I.StartDate
        , I.EndDate
        , I.PriorEndDate 
        , I.NextStart
        , IslandStart = COALESCE(PriorEndDate, EndDate)
        , IslandEnd = I.NextStart 
    FROM CTE_I AS I
    )
SELECT * FROM CTE_G


;WITH CTE_Calendar AS
    (
    SELECT @StartDate AS D
    UNION ALL
    SELECT DATEADD(DAY, 1, D)
    FROM CTE_Calendar
    WHERE D < @EndDate
    )
, CTE_BookingCalendar AS
    (
    SELECT C.D AS BookingStart 
        , DATEADD(DAY, 1, C.D) AS BookingEnd
    FROM CTE_Calendar AS C
    )
, CTE_WhatIsBooked AS
    (
    SELECT B.BookingStart
        , B.BookingEnd
        , S.LocationID
        , S.StartDate
        , S.EndDate
    FROM CTE_BookingCalendar AS B
        LEFT OUTER JOIN @Source AS S ON B.BookingStart BETWEEN S.StartDate AND S.EndDate AND S.EndDate >= B.BookingEnd
    WHERE S.LocationID IS NULL OR S.LocationID = @LocationOfInterest
    ORDER BY B.BookingStart
    )