2012-07-16 78 views
7

我知道這個人可能會遇到一些混亂,我只是想要考慮把它放在一起的最佳方式!我已經在幾個論壇發佈了這個帖子,但我似乎沒有任何運氣。希望有人可以提供一些關於如何做到這一點的建議。從2個日期時間列表可用的時間

實施例表(tbl_Bookings)

ID DateStarted  DateEnded   RoomID 
1 16/07/2012 09:00 16/07/2012 10:00 1 
2 16/07/2012 12:00 16/07/2012 13:00 1 

基本上,我要進入2週日期時間,如16/07/2012 08:30 16/07/2012 13:30和它會查詢我上面的示例表並返回'可用'時間,IE,我想它輸出以下內容。

16/07/2012 08:30 - 16/07/2012 09:00 
16/07/2012 10:00 - 16/07/2012 12:00 
16/07/2012 13:00 - 16/07/2012 13:30 

我的問題是,這是完全可能的SQL?我試圖想到如何在VB中做到這一點,我也在努力。我的想法/曾試圖用羅恩野人的fn_daterange(如下圖所示)

if exists (select * from dbo.sysobjects where name = 'fn_daterange') drop function fn_daterange; 
go 
create function fn_daterange 
(
@MinDate as datetime, 
@MaxDate as datetime, 
@intval as datetime 
) 
returns table 
as 
return 
WITH times (startdate, enddate, intervl) AS 
(
SELECT @MinDate as startdate, @MinDate + @intval - .0000001 as enddate, @intval as intervl 
UNION ALL 
SELECT startdate + intervl as startdate, enddate + intervl as enddate, intervl as intervl 
FROM times 
WHERE startdate + intervl <= @MaxDate 
) 
select startdate, enddate from times; 
go 

然後我會通過使用下面的調用它,但我的問題是,me.DateEnded超出dr.enddate的,因此,次數將是「0」:

SELECT dr.startdate, dr.enddate, count(me.DateStarted) as occurrence 
FROM fn_daterange('16/07/2012 08:30', '16/07/2012 13:30', '00:30:00') dr 
LEFT OUTER JOIN tbl_Bookings me 
ON me.DateStarted BETWEEN dr.startdate AND dr.enddate 
AND me.DateEnded BETWEEN dr.startdate AND dr.enddate) 
GROUP BY dr.startdate, dr.enddate 

任何人都可能認爲這樣做的更好的方法或希望提供一個解決方案,我想現在做到這一點?

在此先感謝!

+0

什麼時間'16/07/2012 09:90'? – 2012-07-16 19:58:51

+0

Tim Schmelte,Easter Egg =) – 2012-07-16 19:59:52

+0

你使用什麼dbms,SQL-Server(哪個版本)?基本上你有一個開始日期時間和一個結束日期時間(因此是一個TimeSpan。現在你想要找到半小時是免費的(沒有預訂)。這是正確的嗎? – 2012-07-16 20:00:54

回答

0

我不知道如何解決使用集合的問題,但以下基於光標的方法應該工作。這是你如何做到這一點在VB或C#:

CREATE FUNCTION GetAvailableTimes 
(
    @MinDate datetime, 
    @MaxDate datetime 
) 
RETURNS @result TABLE 
(
    DateStarted datetime, 
    DateEnded datetime, 
    RoomID int 
) 
AS 
BEGIN 
    DECLARE @DateStarted datetime 
    DECLARE @DateEnded datetime 
    DECLARE @CurrentDate datetime 
    DECLARE @RoomID int 
    DECLARE @CurrentRoom int 

    DECLARE c CURSOR FOR 
     SELECT DateStarted, DateEnded, RoomID 
     FROM tbl_Bookings 
     WHERE DateStarted BETWEEN @MinDate AND @MaxDate 
      OR DateEnded BETWEEN @MinDate AND @MaxDate 
     ORDER BY RoomID, DateStarted 

    SET @CurrentRoom = 0 

    OPEN c 
    FETCH NEXT FROM c 
    INTO @DateStarted, @DateEnded, @RoomID 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 

     IF @CurrentRoom <> @RoomID BEGIN 
      IF @CurrentRoom <> 0 AND @CurrentDate < @MaxDate BEGIN 
       INSERT INTO @result VALUES (@CurrentDate, @MaxDate, @CurrentRoom) 
      END 

      SET @CurrentDate = @MinDate 
      SET @CurrentRoom = @RoomID 
     END 

     IF @CurrentDate < @DateStarted BEGIN 
      INSERT INTO @result VALUES (@CurrentDate, @DateStarted, @CurrentRoom) 
     END 

     SET @CurrentDate = @DateEnded 

     FETCH NEXT FROM c 
     INTO @DateStarted, @DateEnded, @RoomID 
    END 
    CLOSE c 
    DEALLOCATE c 

    IF @CurrentRoom <> 0 AND @CurrentDate < @MaxDate BEGIN 
     INSERT INTO @result VALUES (@CurrentDate, @MaxDate, @CurrentRoom) 
    END 

    RETURN 
END 

以下調用現在得到你正在尋找您的測試數據結果。

SELECT * FROM dbo.GetAvailableTimes('20120716 8:30', '20120716 13:30') 

我也認爲可能有不止一個房間,你在所有的人都在尋找可用時間。

我只是快速測試的功能,因此我很確定仍然有一些邊界案例沒有正確解決。但你應該明白這個主意。

0

我會用下面的邏輯來解決這個問題。爲期望的開始時間和您在數據中看到的第一個開始時間(如果有)之間的期間創建記錄。爲期望的結束時間和您在數據中看到的上次結束時間之間的期間創建記錄(如果有)。然後,爲您所擁有的時間創建中間記錄。

以下查詢有這個想法。我不確定當預期的開始和結束時間處於預定時間段的中間時是否有效。

with const as (select @starttime as StartTime, @endtime as EndTime) 
select * 
from ((Select c.StartTime, MIN(DateStarted), RoomId 
     from tbl_Bookings b cross join const c 
     where b.DateStarted >= c.StartTime 
     group by RoomID 
     having c.StartTime <> MIN(DateStarted) 
    ) union all 
     (Select max(DateEnded), c.EndTime, RoomId 
     from tbl_Bookings b cross join const c 
     where b.DateEnded <= c.EndTime 
     group by RoomID 
     having c.EndTime <> max(DateEnded) 
    ) union all 
     (select * 
     from (select b.DateEnded as DateStarted, min(b.DateStarted) as DateEnded 
      from tbl_Bookings b join 
        tbl_Bookings bnext 
        on b.RoomId = bnext.RoomId and 
        bnext.DateStarted > b.DateStarted cross join 
        const c 
      where b.DateStarted < c.endtime and 
        b.DateEnded > c.StartTime and 
        bnext.DateStart < c.EndTime and 
        bnext.DateEnded > c.StartTime 
      group by b.DateEnded 
      ) b cross join const c 
     where DateStarted <> DateEnded 
    ) 
    ) 

最後一個子查詢相當複雜。它正在進行自聯接以獲得lead()函數的等效項。

2

我相信我在SQL中有一個工作解決方案。這假定tbl_Bookings中的數據是一致的,即給定房間的開始/結束時間不重疊。可能是一種更簡單的方法,但訣竅在於訂購預訂並將結束時間與下列開始時間配對。有兩個額外的查詢聯合在指定的Start之後但在第一次預訂之前獲得任何間隔。同樣適用於End

編輯:新增WHERE NOT EXISTS守衛到最後兩個查詢的情況下@Start@End下跌預訂區間內。

DECLARE @Start DateTime = '05/07/2012 08:30' 
DECLARE @End DateTime = '05/07/2012 13:30' 

;WITH Bookings (RoomId, RowNum, Started, Ended) AS (
    SELECT RoomId, 
    ROW_NUMBER() OVER (PARTITION BY RoomId ORDER BY DateStarted) AS RowNum, 
    DateStarted, DateEnded 
    FROM tbl_Bookings 
) 
SELECT RoomId, B.Ended AS S, C.Started AS E 
FROM Bookings B 
CROSS APPLY (
    SELECT B2.Started FROM Bookings B2 
    WHERE B2.RowNum = B.RowNum + 1 
    AND B2.Started <= @End 
    AND B2.RoomId = B.RoomId 
) C 
WHERE B.Ended >= @Start 

UNION 

-- Show any available time from @Start until the next DateStarted, unless @Start 
-- falls within a booked interval. 
SELECT RoomId, @Start, MIN(DateStarted) 
FROM tbl_Bookings 
WHERE DateStarted > @Start 
    AND NOT EXISTS (
     SELECT 1 FROM Bookings WHERE Started < @Start AND Ended > @Start 
    ) 
GROUP BY RoomId 

UNION 

-- Show any available time from the last DateEnded to @End, unless @End 
-- falls within a booked interval. 
SELECT RoomId, MAX(DateEnded), @End 
FROM tbl_Bookings 
WHERE DateEnded < @End 
    AND NOT EXISTS (
     SELECT 1 FROM Bookings WHERE Started < @End AND Ended > @End 
    ) 
GROUP BY RoomId 

工作SqlFiddle

+1

+1向我介紹SQLFiddle – Qpirate 2012-07-16 21:08:47

+0

只是爲了「完整性」,我在[data.se] [here](http://data.stackexchange.com/stackoverflow/query/75613/so11511634)中複製了此內容。 – 2012-07-18 04:44:28

相關問題