我想获得给定月份的第一个工作日。我生成一个假期表并将其与常规工作日检查结合使用,以查找一个月的第一个工作日。似乎有效。但是,当我使用第一个月作为输入时,例如(2020, 1)功能超时。这样的每一年,每隔一个月都有效。
CREATE FUNCTION FirstBusinessDay(@year INT, @month INT) RETURNS DATETIME
AS BEGIN
DECLARE @calendar TABLE (Name varchar(80), Date DATETIME)
INSERT INTO @calendar SELECT * FROM dbo.HolidayTable(@year)
DECLARE @d DATETIME = DATEFROMPARTS(@year, @month, 1)
DECLARE @isHoliday bit
SELECT @isHoliday = CASE WHEN Name IS NULL THEN 0 ELSE 1 END
FROM @calendar WHERE Date = @d
WHILE DATEPART(DW, @d+@@DATEFIRST-1) > 5 or @isHoliday = 'true'
BEGIN
SET @d = DATEADD(DAY, 1, @d)
SELECT @isHoliday = CASE WHEN Name IS NULL THEN 0 ELSE 1 END
FROM @calendar WHERE Date = @d
END
RETURN @d
END;
GO
用法示例
select dbo.FirstBusinessDay(2020, 1) as 'First Workday'; -- timeout
select dbo.FirstBusinessDay(2020, 2) as 'First Workday'; -- works
select dbo.FirstBusinessDay(2020, 3) as 'First Workday'; -- works
select dbo.FirstBusinessDay(2021, 7) as 'First Workday'; -- works
select dbo.FirstBusinessDay(2020, 12) as 'First Workday'; -- works
select dbo.FirstBusinessDay(2021, 1) as 'First Workday'; -- timeout
select dbo.FirstBusinessDay(2022, 1) as 'First Workday'; -- timeout
如您所见,有一种模式,每次使用第一个月都会超时。谁能发现这个问题?
关于以这种方式设置变量的备注部分说:
如果SELECT语句不返回任何行,则该变量将保留其当前值。
...因此,发生的事情非常清楚:元旦是假期,设置@isHoliday为true。由于在没有行@calendar那些没有节假日,它永远不能被设置为false。其他月份仅工作,因为默认@isHoliday值为0- false。
就是说,您真正想要的是一个真正的日历表,每个日期列出一个日历表,并列出其他可索引的列。它将您的函数变成一个简单的查询:
SELECT MIN(calendar_date)
FROM Calendar
WHERE calendar_date >= DATEFROMPARTS(@year, @month, 1)
AND is_holiday = 'false'
AND day_of_week_iso < 6
日历表可能是进行维度分析的最有用的表,尤其是对于各种聚合(例如,“按月分组的每个销售”),因为日历表将它们变成了范围查询,而不需要使用DATEPART。
分享改善这个答案
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。