如何在2次SQL Server之间找到可用或空闲的时隙

时间:2018-06-18 12:55:18

标签: c# sql sql-server tsql gaps-and-islands

我有以下表结构:

CREATE TABLE [dbo].[ReservationDetails]
(
    [SessionID] [int] IDENTITY(1,1) NOT NULL,
    [UserID] [bigint] NOT NULL,
    [ExpectedStart] [datetime] NOT NULL,
    [ExpectedEnd] [datetime] NOT NULL,

    CONSTRAINT [PK_dbo.ReservationDetails] 
        PRIMARY KEY CLUSTERED ([SessionID] ASC)
) ON [PRIMARY]

以下是一些数据:

INSERT INTO ReservationDetails (UserID,ExpectedStart,ExpectedEnd)
VALUES (1, '1900-01-01 09:15:00.000', '1900-01-01 09:30:00.000'),
       (2, '1900-01-01 10:00:00.000', '1900-01-01 10:30:00.000')

从上表&数据,我想在上午9点到11点半之间找到可用的时段。

此处UserID = 1已预订时间为09:15 AM至09:30 AM& UserID = 2预订时间为上午10:00至上午10:30

我需要在09:00 AM到11:30 AM之间列出可能的免费/可用时段。我们只需要显示空闲/可用时间就没有时隙定时。

它们如下所示。

09:00 AM TO 09:15 AM
09:30 AM TO 10:00 AM
10:30 AM TO 11:30 AM

我需要帮助才能获得免费/可用的广告位

2 个答案:

答案 0 :(得分:4)

这是一个空白和岛屿类型的问题。

请谷歌了解更多信息。

这是 example solution

declare @startTime datetime= '1900-01-01 09:00:00.000', @EndTime datetime='1900-01-01 11:30:00.000';

; 
with allts as 
(
select top (select datediff(mi,@startTime,@EndTime)+1)
mislot=dateadd(mi,row_number() over(order by (select null))-1,@startTime),
    rn=row_number() over(order by (select null))
from 
sys.objects t1 cross join
sys.objects t2
),

 ts as 
 ( select a.mislot,a.rn, rn2= row_number() over ( order by rn asc)
  from allts  a
outer apply(
    select flag=1 from ReservationDetails r
  where a.mislot > ExpectedStart and  a.mislot < ExpectedEnd
  )b
  where b.flag is null
  )
select startavl=min(mislot), endavl=max(mislot) from ts
group by rn2-rn
order by startavl asc

答案 1 :(得分:0)

对于c#中的解决方案,我有以下代码。我没有测试过它们。 我们的想法是声明一个包含(持续时间分钟)条目的数组列表。 你有一个对象,在这个对象上你可以阻止时隙。如果阻止插槽,则数组列表中的条目将在此分钟设置为false。 要获得空闲时间段,您可以遍历列表。每次如果在假之后存在真实,则您有空闲时段的开始时间。插槽是空闲的,直到下一个假(空闲插槽的结束时间)。所以你可以获得免费插槽。

namespace xy
{
  class test
  {
    List<bool> slots = new List<bool>();
    DateTime start;
    DateTime end;

    public test(DateTime start, DateTime end)
    {
        this.start = start;
        this.end = end;
        for(int i=1; i <= (end.Hour * 60) + end.Minute; i++)
        {
            slots.Add(true);
        }
    }


    public void Block_Slots(DateTime startBlock, DateTime endBlock)
    {
        for(int i = (startBlock.Hour * 60) + startBlock.Minute; i<= (endBlock.Hour * 60) + endBlock.Minute; i++)
        {
            slots[i] = false;
        }
    }

    public List<Slot> GetFreeSlots()
    {
        List<Slot> tmp = new List<Slot>();
        Nullable<DateTime> startPeriod = null;
        Nullable<DateTime> endPeriod = null;
        int counter = 1;
        foreach(bool entry in slots)
        {
            if (entry)
            {
                if(startPeriod == null)
                    startPeriod = new DateTime(this.start.Year, this.start.Month, this.start.Day, counter / 60 + start.Hour, counter % 60 + start.Minute, 0);
                else
                {


                }

            }
            else
            {
                if(startPeriod != null)
                {
                    endPeriod = new DateTime(this.start.Year, this.start.Month, this.start.Day, counter-1 / 60, counter-1 % 60, 0);
                    tmp.Add(new Slot((DateTime)startPeriod, (DateTime)endPeriod));
                    startPeriod = null;
                    endPeriod = null;



                }else{}
            }
            counter++;
        }
        return tmp;
    }


}

class Slot
{
    DateTime start;
    DateTime end;
    public Slot(DateTime start, DateTime end)
    {
        this.start = start;
        this.end = end;
    }
}
}