繁体   English   中英

使用c#和SQL检查日期范围的最有效方法

[英]Most efficient way to check a range of dates using c# and SQL

我正在为我们公司正在进行的笔记本电脑刷新预订系统。 我需要能够计算哪些天有可用的插槽并将它们返回到日历控件上呈现(即,如果一天有可用天数,则可以选择,否则不是。

逻辑如下:

  • 技术人员每天可以制作3台笔记本电脑。
  • 在任何一天,可能有1,2或3名技术人员。
  • 一张桌子将保存已经预订的房产

每天可用的插槽总数是(伪代码):

((laptops per day) * (technicians available)) - slots already booked

我的问题是,最有效的方法是什么? 我想它最好在SQL端完成,其功能是返回一个带有可用插槽的日期表。 (只要至少有一个插槽可用,无论有多少都没关系。)

到目前为止,我可以全面了解这一切。 我坚持的一点是,我不想拥有所有可能日期的表,因为它似乎有点低效。 我希望能够做的是在将来的3到3个月之间有效地迭代,并从那里计算可用的日期。

我可以在c#中执行此操作,但它对我来说效率低下,因为它必须在每个可能的日期保持命中SQL服务器。 在SQL方面似乎更好,但我不知道如何以这种方式迭代可能的日期。

解决这个问题

使用@Chris的方法,我可以获得一系列日期,其中插槽书籍不超过设定的最大值:

DECLARE @startDate DATE
DECLARE @endDate DATE

SET @startDate = GETDATE()
SET @endDate = DATEADD(m,3,@startDate)
;
WITH dates(Date) AS 
(
    SELECT @startdate as Date
    UNION ALL
    SELECT DATEADD(d,1,[Date])
    FROM dates 
    WHERE DATE < @enddate
)

SELECT Date
FROM dates 
EXCEPT
SELECT date
        FROM tl_sb_booking
        GROUP BY date
        HAVING COUNT(date) < 3

这只是设置3个预订的任意最多。 下一步是添加技术人员的可用性!

这个答案解决了问题的一部分:“我希望能够做的是在现在和未来3个月之间的一系列日期中有效地进行迭代,并从那里计算可用的日期。”

如果您使用的是MSSQL,那么CTE可能会有所帮助。 要动态生成您的日期范围代码,可以使用以下代码:

DECLARE @startDate DATE
DECLARE @endDate DATE

SET @startDate = GETDATE()
SET @endDate = DATEADD(m,3,@startDate)
;
WITH dates(Date) AS 
(
    SELECT @startdate as Date
    UNION ALL
    SELECT DATEADD(d,1,[Date])
    FROM dates 
    WHERE DATE < @enddate
)

SELECT Date
FROM dates

最后一个SELECT然后可以连接到其他表以获取该日期的数据,进行计算等。

但是,这不一定是执行此操作的最佳方式。 假设您有一些方法可以获得每天有多少工程师免费的列表,那么就不需要迭代任何其他日期(因为您知道在这些日期没有可用性)。 所以为此目的:

SELECT count(1), Date
From EngineerWorkDays
GROUP BY Date
Where Date>= Getdate()
and Date < DATEADD(m,3,Getdate())

将返回可能正在进行工作的日期列表。 获得已分配工作的另一个选择将为您提供所需的所有数据。 在c#中的显示代码中,您可以每天迭代并检查数据集中是否有相关数据(工程师是否可用,有多少,已经预订了多少工作等)。

并且不要忘记,如果这是一个共享的应用程序,以检查在预订之前还有空间,以防其他人在您的初始查询后预订了某些内容。

尝试这个:

Select [DatesAvailable] From TableName
Where [DatesAvailable] Between BeginningDate And DateAdd(m, 3, BeginningDate) And
      SlotsAvailable > 0

这应该会给你任何在接下来的3个月内有空位的日期......

这是一种方法:

DECLARE @iToday As INT; SET @iToday = CAST(GetDate() As INT);
DECLARE @iDays As INT;  SET @iDays = 90;

WITH cte_0to9 As
(
    Select 0 As Num UNION ALL Select 1 UNION ALL Select 2 UNION ALL Select 3
    UNION ALL Select 4 UNION ALL Select 5 UNION ALL Select 6 UNION ALL Select 7
    UNION ALL Select 8  UNION ALL Select 9
)
, cte_0to99 As
(
    SELECT  (Tens.Num * 10) + Ones.Num As Num
    FROM        cte_0to9 As Ones
    CROSS JOIN  cte_0to9 As Tens
)
, cteDays As 
(
    SELECT  CAST(@iToday + Num As DATETIME) As PossibleDate
    FROM    cte_0to99
    WHERE   Num <= @iDays
)
, cteTechnicianUtilization As
(
    SELECT  t.Technician,
            d.PossibleDate,
            (Select COUNT(*) From Bookings b
             Where b.Technician = t.Technician
               And b.BookDate = d.PossibleDate) As SlotsUsed
    FROM    Technicians As t
    CROSS JOIN cteDays d
)
SELECT  PossibleDate, SUM(Util-3) As TotalAvailableSlots
FROM    cteTechnicianUtilization
WHERE   Util < 3
GROUP BY PossibleDate
HAVING  SUM(Util-3) > 0

请注意,这种方法虽然更长(代码方式)比使用递归更有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM