我有一组时期,如:
CREATE TABLE `periods` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`start_at` date DEFAULT NULL,
`end_at` date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
LOCK TABLES `periods` WRITE;
INSERT INTO `periods` (`id`, `start_at`, `end_at`)
VALUES
(1,'2013-04-29','2013-04-30'),
(2,'2013-05-05','2013-05-10'),
(3,'2013-05-10','2013-05-15'),
(4,'2013-05-15','2013-05-16'),
(5,'2013-05-18','2013-05-19'),
(6,'2013-05-19','2013-05-25');
UNLOCK TABLES;
我的预期愿望是了解一个特定时期是否被一个或多个时期完全覆盖的最佳方式。
例如:
1)从null
到2013-04-29
获取2013-05-10
请求,导致从2013-04=30
到2013-05-05
2)获取true
到2013-05-06
的请求的期间ID(或至少2013-05-15
或任何内容)
更新:主要目标是定义给定时间段(从2013-05-06
到2013-05-15
按照示例2)是否可以租用。数据库中的时段是可用的租赁季节,因此如果不包括任何一天,则无法租用整个住宿。
答案 0 :(得分:2)
试试这些。最重要的是,如果Shortfall > 0
,则您无法预订租借。
MSSQL - 这就是我的工作原理
DECLARE @start DATETIME = '2013-04-29' -- this will depend on your dateformat
DECLARE @end DATETIME = '2013-05-10'
DECLARE @days INT = DATEDIFF(D,@start, @end) -- this is how many days we actually want to stay
DECLARE @unusedDays INT = 0 -- this will be the number of unused days from the rental periods in which our start and end dates fall
SELECT @UnusedDays = DATEDIFF(D,@end,end_at) FROM PERIODS WHERE (@end > start_at AND @end <= end_at) -- how many spare days are there in the final period?
SELECT @UnusedDays = @UnusedDays + DATEDIFF(D,start_at, @start) FROM PERIODS WHERE (@start >= start_at AND @start < end_at) -- how many spare days are there in the start period?
SELECT @days + @UnusedDays - SUM(DATEDIFF(D,start_at,end_at)) AS Shortfall, -- total shortfall in days. Zero if we are okay to rent
SUM(DATEDIFF(D,start_at,end_at)) AS AvailableDays, -- total number of days available in all periods covering our chosen rental period
@days AS DesiredDays, -- number of days we want to rent
@UnusedDays AS WastedDays -- number of wasted days (if we start or end our rental mid-period)
FROM PERIODS
WHERE (@start >= start_at AND @start < end_at) -- period in which our selected rental starts
OR (end_at < @end AND start_at > @start) -- period completely within our selected rental
OR (@end > start_at AND @end <= end_at) -- period in which our selected rental ends
这提供了如下输出:
-- if you have @start = '2013-05-05'
-- and @end = '2013-05-13'
-- then you get
Shortfall AvailableDays DesiredDays WastedDays
0---------10------------8-----------2---------
-- if you have @start = '2013-04-29'
-- and @end = '2013-05-10'
-- then you get
Shortfall AvailableDays DesiredDays WastedDays
5---------6-------------11----------0---------
MySQL - 这就是你真正想要的东西
SET @start = '2013-04-29';
SET @end = '2013-05-10';
SET @days = DATEDIFF(@end, @start); -- this is how many days we actually want to stay
SET @UnusedDays = 0; -- this will be the number of unused days from the rental periods in which our start and end dates fall
SELECT @UnusedDays := DATEDIFF(end_at,@end) FROM PERIODS WHERE (@end > start_at AND @end <= end_at); -- how many spare days are there in the final period?
SELECT 'hello';
SELECT @UnusedDays := @UnusedDays + DATEDIFF(@start, start_at) FROM PERIODS WHERE (@start >= start_at AND @start < end_at); -- how many spare days are there in the start period?
SELECT 'hello';
SELECT @days + @UnusedDays - SUM(DATEDIFF(end_at, start_at)) AS Shortfall, -- total shortfall in days. Zero if we are okay to rent
SUM(DATEDIFF(end_at, start_at)) AS AvailableDays, -- total number of days available in all periods covering our chosen rental period
@days AS DesiredDays, -- number of days we want to rent
@UnusedDays AS WastedDays -- number of wasted days (if we start or end our rental mid-period)
FROM PERIODS
WHERE (@start >= start_at AND @start < end_at) -- period in which our selected rental starts
OR (end_at < @end AND start_at > @start) -- period completely within our selected rental
OR (@end > start_at AND @end <= end_at); -- period in which our selected rental ends
答案 1 :(得分:1)
虽然我喜欢@Dommer的方法和包含的细节(非常感谢),我更喜欢@snoyes在IRC#mysql上提供的方法。
SELECT IF(COUNT(*), false, true) AS rentable
FROM(
SELECT
a.end_at AS START,
Min(b.start_at) AS END
FROM periods AS a
JOIN periods AS b ON a.end_at <= b.start_at
GROUP BY a.end_at
HAVING a.end_at < MIN(b.start_at)
) AS gaps
WHERE
gaps.START < '2013-05-17' AND gaps.END > '2013-05-05';
也可以使用SQLFiddle。
有关详细信息,初始引用来自http://www.artfulsoftware.com/infotree/qrytip.php?id=577
答案 2 :(得分:0)
Select ID from `periods`
where
start_at >= <Your_given_start>
and end_at <= <Your_given_end>
不幸的是,如果有一段时间,这只会返回一些东西。
答案 3 :(得分:0)
您可以在一个查询中执行此操作。以下查询假定您已定义@StartDate
和@EndDate
。
关键的想法是,您只需要在开始日期前一天或结束日期后一天进行测试。如果有一个没有覆盖的时期,那么它将在此期间出现。以下查询计算测试日期以及它们是否可用:
select TestDay, COUNT(p.id)
from ((select p.Start_at - 1 as TestDay
from #Periods p
where p.start_at > @StartDate and p.start_at <= @EndDate
)
union all
(select p.End_at
from #periods p
where p.start_at >= @StartDate and p.start_at < @EndDate
)
) t left outer join
#periods p
on t.TestDay >= p.start_at and t.TestDay < p.end_at
group by TestDay;
这是您需要的更多信息。您只需要第一种情况下的0
和第二种情况下的1
。这只是测试上述查询中的p.id
是否为NULL
:
select MAX(case when p.id is null then 1 else 0 end)
from ((select p.Start_at - 1 as TestDay
from #Periods p
where p.start_at > @StartDate and p.start_at <= @EndDate
)
union all
(select p.End_at
from #periods p
where p.start_at >= @StartDate and p.start_at < @EndDate
)
) t left outer join
#periods p
on t.TestDay >= p.start_at and t.TestDay < p.end_at;
此查询可能有一个错误(取决于结束日期是否有可用性)。这样的问题很容易解决。