差距和岛屿
Gaps and Island
我有一个带有 StartDate 和 EndDate 的 table。我想得到丢失的日期和我的脚本。但是比如
位置 ID 开始日期结束日期
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);
我得到的输出是,
开始日期结束日期
2020-01-06 2020-01-09
2020-01-16 2020-01-31
但我希望输出为,
开始日期结束日期
2020-01-03 2020-01-04
2020-01-05 2020-01-10
2020-01-15 2020-01-31
我可以做哪些改变?
一个位置可以从晚上预定到早上。所以 StartDate 晚上到 EndDate 早上。因此,该位置在 EndDate 之夜将免费,除非已被预订。此外,位置将在开始日期早上免费。
1 月 1 日至 1 月 3 日已预订 - 即从第 1 晚到第 3 天早上。下一次预订仅在第 4 晚。因此,该位置从第 3 晚到第 4 天早上也是免费的。所以我需要结果在一行中有第 3 个作为开始日期和 4thJan 作为结束日期。希望这是清楚的。
谢谢
我不会说谎,我可能把它复杂化了一点,但这是我的方向,所以我看到了最后。但是,我确实将您的 rCTE 替换为 Tally,对于更大的集合,它应该(显着)更高效。您可能还需要在 PlaceID
上添加 PARTITION BY
和 GROUP BY
子句,但由于示例基于 1 个地方,因此我没有实现它。
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 N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP(DATEDIFF(DAY,@StartDateOfInterest,@EndDateOfInterest)+1)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 AS I
FROM N N1, N N2, N N3), --1000 days
Dates AS(
SELECT DATEADD(DAY, I, @StartDateOfInterest) AS [Date]
FROM Tally),
Gaps AS(
SELECT D.[Date],
CASE LAG(DATEADD(DAY,1,D.[Date]),1,D.[Date]) OVER (ORDER BY D.[Date]) WHEN D.Date THEN 1 ELSE 0 END AS [Check]
FROM Dates D
LEFT JOIN @t t ON D.[Date] >= t.StartDate
AND D.[Date] < t.EndDate
WHERE t.PlaceID IS NULL),
Grps AS(
SELECT [Date],
COUNT(CASE [Check] WHEN 0 THEN 1 END) OVER (ORDER BY [Date] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Grp
FROM Gaps)
SELECT MIN([Date]) AS StartDate,
MAX(CASE [Date] WHEN @EndDateOfInterest THEN [Date] ELSE DATEADD(DAY,1,[Date]) END) AS EndDate
FROM Grps
GROUP BY Grp;
我有一个带有 StartDate 和 EndDate 的 table。我想得到丢失的日期和我的脚本。但是比如
位置 ID 开始日期结束日期
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);
我得到的输出是,
开始日期结束日期
2020-01-06 2020-01-09
2020-01-16 2020-01-31
但我希望输出为,
开始日期结束日期
2020-01-03 2020-01-04
2020-01-05 2020-01-10
2020-01-15 2020-01-31
我可以做哪些改变?
一个位置可以从晚上预定到早上。所以 StartDate 晚上到 EndDate 早上。因此,该位置在 EndDate 之夜将免费,除非已被预订。此外,位置将在开始日期早上免费。
1 月 1 日至 1 月 3 日已预订 - 即从第 1 晚到第 3 天早上。下一次预订仅在第 4 晚。因此,该位置从第 3 晚到第 4 天早上也是免费的。所以我需要结果在一行中有第 3 个作为开始日期和 4thJan 作为结束日期。希望这是清楚的。
谢谢
我不会说谎,我可能把它复杂化了一点,但这是我的方向,所以我看到了最后。但是,我确实将您的 rCTE 替换为 Tally,对于更大的集合,它应该(显着)更高效。您可能还需要在 PlaceID
上添加 PARTITION BY
和 GROUP BY
子句,但由于示例基于 1 个地方,因此我没有实现它。
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 N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP(DATEDIFF(DAY,@StartDateOfInterest,@EndDateOfInterest)+1)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 AS I
FROM N N1, N N2, N N3), --1000 days
Dates AS(
SELECT DATEADD(DAY, I, @StartDateOfInterest) AS [Date]
FROM Tally),
Gaps AS(
SELECT D.[Date],
CASE LAG(DATEADD(DAY,1,D.[Date]),1,D.[Date]) OVER (ORDER BY D.[Date]) WHEN D.Date THEN 1 ELSE 0 END AS [Check]
FROM Dates D
LEFT JOIN @t t ON D.[Date] >= t.StartDate
AND D.[Date] < t.EndDate
WHERE t.PlaceID IS NULL),
Grps AS(
SELECT [Date],
COUNT(CASE [Check] WHEN 0 THEN 1 END) OVER (ORDER BY [Date] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Grp
FROM Gaps)
SELECT MIN([Date]) AS StartDate,
MAX(CASE [Date] WHEN @EndDateOfInterest THEN [Date] ELSE DATEADD(DAY,1,[Date]) END) AS EndDate
FROM Grps
GROUP BY Grp;