Lücken und Inseln
Ich habe eine Tabelle mit StartDate und EndDate. Ich wollte das fehlende Datum bekommen und das Skript, das ich habe, macht es. Aber wenn diese Daten gegeben werden:
LocationID StartDate EndDate
---------- ---------- ----------
1 2020-01-01 2020-01-03
1 2020-01-04 2020-01-05
1 2020-01-10 2020-01-15
Diese Abfrage:
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);
Gibt diese Ausgabe zurück:
STARTDATE ENDDATE
--------- ----------
2020-01-06 2020-01-09
2020-01-16 2020-01-31
Aber ich wollte die Ausgabe als:
STARTDATE ENDDATE
--------- ----------
2020-01-03 2020-01-04
2020-01-05 2020-01-10
2020-01-15 2020-01-31
Welche Änderungen kann ich vornehmen?
Bearbeitet, um hinzuzufügen: Ein Standort kann von Nacht bis Morgen gebucht werden. Also StartDate Night bis EndDate Morning. SO ist der Standort am EndDate-Abend kostenlos, sofern er nicht gebucht ist. Außerdem ist der Standort am Startdate Morning kostenlos.
Der 1. Januar bis 3. Januar ist gebucht - das heißt von der 1. Nacht bis zum 3. Morgen. Die nächste Buchung erfolgt erst am 4. Abend. Die Lage ist also auch von der 3. Nacht bis zum 4. Morgen frei. Also würde ich das Ergebnis brauchen, um 3. ein als Startdatum und 4. Januar als Enddatum in einer Zeile zu haben. Hoffe das ist klar.
Antworten
Dafür brauchst du wirklich keinen Cte
Die Fensterfunktion LEAD kann das tun, was Sie brauchen
Es kann verfeinert werden, wenn die Daten übereinstimmen
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 GOPlaceID | EndDate | Nächstes Datum ------: | : --------- | : --------- 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 <> hier fummeln
Die Antwort von @nbk wird Ihnen das bringen, was Sie wollen. Ich füge dies hier ein, da es sich für Sie als interessant erweisen kann. obwohl es nicht vollständig ist. Im Moment wird die Liste der möglichen Buchungstermine angezeigt und es wird angezeigt, ob die Buchung gemäß den von Ihnen festgelegten Regeln erfolgt ist oder nicht. Es kann als Kalenderansicht oder ähnliches für Sie nützlich sein.
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
)