如何找到 2 次 SQL 服务器之间的可用或空闲时间段

How to find available or free timeslots between 2 times SQL Server

我有以下 table 结构:

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')

从上面的 table 和数据中,我想找到上午 9 点到 11:30 之间的可用时间段。

这里 UserID = 1 已经预订了从 09:15 上午到 09:30 上午 & UserID = 2 预订了 10:00 上午到 10:30 上午

的时间

我们需要列出在 09:00 上午到 11:30 上午之间可能的 free/available 时间段。插槽计时没有间隔,我们只需要显示 free/available 计时。

它们如下所示。

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

我需要帮助才能获得 free/available 个插槽

这是一个间隙和孤岛类型的问题。

请google了解更多。

这是一个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

对于 c# 中的解决方案,我有以下代码。我没有测试它们。 这个想法是用(持续时间分钟)条目声明一个数组列表。 你有一个对象,在这个对象上你可以阻塞时隙。如果您阻止插槽,阵列列表中的条目将在这一分钟内设置为 false。 要获得空闲时间段,您可以遍历列表。每次如果在 false 之后有 true,你就有空闲槽的开始时间。该槽在下一个 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;
    }
}
}