计算两个日期之间的工作日数-T-SQL?
我意识到不同的解决方案会对“工作日”的含义产生不同的影响,但就我而言,我指的是周一到周五(包括周一到周五) 基本上,我已经创建了一个函数来为我进行计算,而我当前的解决方案是有效的。我的担心(以及提出这个问题的原因)是,我担心这是一种不好的实现方法,因为调用函数的频率非常高。在过去的3个月中,它在一个生产系统上被调用了1200万次,平均工作时间为44ms 这让我怀疑这是否是实现解决方案的正确方法 首先,这里是我创建的函数:计算两个日期之间的工作日数-T-SQL?,sql,sql-server,performance,query-optimization,Sql,Sql Server,Performance,Query Optimization,我意识到不同的解决方案会对“工作日”的含义产生不同的影响,但就我而言,我指的是周一到周五(包括周一到周五) 基本上,我已经创建了一个函数来为我进行计算,而我当前的解决方案是有效的。我的担心(以及提出这个问题的原因)是,我担心这是一种不好的实现方法,因为调用函数的频率非常高。在过去的3个月中,它在一个生产系统上被调用了1200万次,平均工作时间为44ms 这让我怀疑这是否是实现解决方案的正确方法 首先,这里是我创建的函数: CREATE FUNCTION [dbo].[fn_WorkDays]
CREATE FUNCTION [dbo].[fn_WorkDays]
(
@StartDate DATETIME,
@EndDate DATETIME = NULL --@EndDate replaced by @StartDate when DEFAULTed
)
RETURNS INT
AS
BEGIN
--===== Declare local variables
--Temporarily holds @EndDate during date reversal
DECLARE @Swap DATETIME
--===== If the Start Date is null, return a NULL and exit
IF @StartDate IS NULL
RETURN NULL
--===== If the End Date is null, populate with Start Date value
-- so will have two dates (required by DATEDIFF below)
IF @EndDate IS NULL
SELECT @EndDate = @StartDate
--===== Strip the time element from both dates (just to be safe) by converting
-- to whole days and back to a date. Usually faster than CONVERT.
-- 0 is a date (01/01/1900 00:00:00.000)
SELECT @StartDate = DATEADD(dd,DATEDIFF(dd,0,@StartDate),0),
@EndDate = DATEADD(dd,DATEDIFF(dd,0,@EndDate) ,0)
--===== If the inputs are in the wrong order, reverse them
IF @StartDate > @EndDate
SELECT @Swap = @EndDate,
@EndDate = @StartDate,
@StartDate = @Swap
--===== Calculate and return the number of workdays using the
-- input parameters. This is the meat of the function.
-- This is really just one formula with a couple of parts
-- that are listed on separate lines for documentation
-- purposes.
RETURN (
SELECT
--Start with total number of days including weekends
(DATEDIFF(dd,@StartDate,@EndDate)+1)
--Subtact 2 days for each full weekend
-(DATEDIFF(wk,@StartDate,@EndDate)*2)
--If StartDate is a Sunday, Subtract 1
-(CASE WHEN DATENAME(dw,@StartDate) = 'Sunday'
THEN 1
ELSE 0
END)
--If EndDate is a Saturday, Subtract 1
-(CASE WHEN DATENAME(dw,@EndDate) = 'Saturday'
THEN 1
ELSE 0
END)
)
END
作为其使用的一个简单示例,我将运行以下类型的查询:
SELECT MYTABLE.EntryDate
,dbo.fn_WorkDays(MYTABLE.EntryDate, getutcdate()) as WorkingDays
FROM MYTABLE
MyTable可以包含5000行,在EntryDate列中所有行的日期都不同(5000次函数调用)
我的问题是我在做这件事的过程中遗漏了一些东西,为这件事创建一个查找表是否有益(但这是很多日期的组合)
如果您有任何想法、改进或建议,我们将不胜感激。这里有两个问题:
第一个更容易,因为关系数据库将具有帮助您的功能。第二个更难,也更可变,因为它会随着区域设置和业务的变化而变化。我认为UDF tbh没有什么可以做的,在SQL中这样在运行时计算它总是会受到一定程度的影响 因此,理想情况下(这可能不可能,因为我不知道全部情况),我认为我应该将工作日数存储在表中,并在创建记录时计算一次。如果这是不可能的(即,当创建记录时,您没有“结束日期”,因此必须使用“现在”来计算),那么我会考虑安排一个夜间作业,并重新计算所有这些特定记录,以便每天更新这些记录,然后在输入“结束日期”时,该记录未包含在此批处理更新中 这样做的好处是,您可以将计算转移到一个更安静的时间段,并且每天只进行一次计算。查询变得更简单,性能也更高,因为它可以从表中读取工作日数
如果这不是一个选项,那么我建议在前端进行计算,删除数据库中的点击。看看这个答案并比较注释:您是否可以添加一个额外的字段(计算字段)并仅在值发生变化时用天内的差值进行更新?我的意思是,每次获得差异的意义是什么?总是将存储的日期与今天进行比较。。。所以每天至少要更新一次(这是一个选项)我的需求的可能副本比这简单,我不关心假期,基本上不包括周末。。。。我的解决方案确实做到了这一点,我只是想确定我错过了一个技巧,并且正在以最有效的方式执行解决方案。圣诞节、新年等等-不必担心这些?然后这是一个更容易的问题。现在不是。不,我只是关心我的问题解决方案的实现。因为计算总是基于今天,我需要每天分配一个值,而不是在创建记录时分配(或者在创建记录时初始化值?),“打得好!”西蒙——我怀疑会是这样。但我认为值得考虑每晚更新的方法。每天更新一次,可以极大地提高报告性能,特别是如果计算在一天中进行多次