我需要帮助创建一个sql server(2012)函数,当给出以下变量时
Monday True/False Tuesday True/False Wednesday True/False Thursday True/False Friday True/False Saturday True/False Sunday True/False Date1 mm/dd/yyyy Type Next/Previous
它将返回Date1
的下一个(或上一个)工作日的日期例如,如果Date1是12/22/2014(星期一),并且传递下面的参数,它将返回2014年12月26日(星期五)
Monday True Tuesday False Wednesday False Thursday False Friday True Saturday True Sunday True Date1 12/22/2014 Type Next
答案 0 :(得分:2)
以下查询计算下一个有效的"日"在一周的任何一天之后。它计算当天的天数。
with days as (
select 1 as dow, 'Monday' as name, @Monday as flag union all
select 2, 'Tuesday', @Tuesday union all
select 3, 'Wednesday', @Wednesday union all
select 4, 'Thursday', @Thursday union all
select 5, 'Friday', @Friday union all
select 6, 'Saturday', @Saturday union all
select 7, 'Sunday', @Sunday
)
select d.*, d2.dow as next_dow,
(case when d2.dow > d.dow then d2.dow - d.dow else d2.dow - d.dow + 7 end) as days_to_next
from days d cross apply
(select top 1 d2.dow
from days d2
where d2.flag = 'true'
order by (case when d2.dow > d.dow then 1 else 2 end), d2.dow
) d2;
下一步就是查找你想要的日子:
with days as (
select 1 as dow, 'Monday' as name, @Monday as flag union all
select 2, 'Tuesday', @Tuesday union all
select 3, 'Wednesday', @Wednesday union all
select 4, 'Thursday', @Thursday union all
select 5, 'Friday', @Friday union all
select 6, 'Saturday', @Saturday union all
select 7, 'Sunday', @Sunday
)
select dateadd(day,
(case when d2.dow > d.dow then d2.dow - d.dow else d2.dow - d.dow + 7 end),
@Date1
)
from days d cross apply
(select top 1 d2.dow
from days d2
where d2.flag = 'true'
order by (case when d2.dow > d.dow then 1 else 2 end), d2.dow
) d2
where d.dow = datename(weekday, @Date1);
当然,如果使用非英语国际化设置,datename()
可能会返回非英语名称。如果该逻辑不起作用,则可以调整查询。
答案 1 :(得分:1)
您必须先创建table type variable
:
CREATE TYPE BusinessDateTableType AS TABLE
(
[WeekDay] VARCHAR(50),
IsBusinessDate BIT
);
然后创建一个带有上述类型的表值参数的函数:
CREATE FUNCTION UDF_GetNextBusinessDay
(
@businessDates BusinessDateTableType READONLY,
@type VARCHAR(10),
@day DATE
)
RETURNS DATE
AS
BEGIN
-- Declare the return variable here
DECLARE @nextBusinessDate DATE
;WITH cte AS (
SELECT CASE
WHEN @type = 'Next' THEN 1
WHEN @type = 'Previous' THEN -1
END AS i
UNION ALL
SELECT CASE
WHEN @type = 'Next' THEN i + 1
WHEN @type = 'Previous' THEN i -1
END AS i
FROM cte
WHERE ABS(i) < 7
)
SELECT TOP 1 @nextBusinessDate = DATEADD(day, i, @day)
FROM cte AS d1
INNER JOIN @businessDates AS d2 ON DATENAME(DW, DATEADD(day, i, @day)) = d2.WeekDay
WHERE d2.IsBusinessDate = 1
ORDER BY ABS(i)
-- Return the result of the function
RETURN @nextBusinessDate
END
修改强>
我们可以使用七个BIT
类型变量轻松替换UDF中的表类型变量,然后在UDF中使用table variable
并使用这些变量的值填充它:
CREATE FUNCTION UDF_GetNextBusinessDay2
(
@IsMonWorkingDay BIT,
@IsTueWorkingDay BIT,
@IsWedWorkingDay BIT,
@IsThuWorkingDay BIT,
@IsFriWorkingDay BIT,
@IsSatWorkingDay BIT,
@IsSunWorkingDay BIT,
@type VARCHAR(10),
@day DATE
)
RETURNS DATE
AS
BEGIN
-- Declare the return variable here
DECLARE @nextBusinessDate DATE
DECLARE @businessDates TABLE ([WeekDay] VARCHAR(50), IsBusinessDate BIT)
INSERT INTO @businessDates VALUES
('Monday', @IsMonWorkingDay),
('Tuesday', @IsTueWorkingDay),
('Wednesday', @IsWedWorkingDay),
('Thursday', @IsThuWorkingDay),
('Friday', @IsFriWorkingDay),
('Saturday', @IsSatWorkingDay),
('Sunday', @IsSunWorkingDay)
;WITH cte AS (
SELECT CASE
WHEN @type = 'Next' THEN 1
WHEN @type = 'Previous' THEN -1
END AS i
UNION ALL
SELECT CASE
WHEN @type = 'Next' THEN i + 1
WHEN @type = 'Previous' THEN i -1
END AS i
FROM cte
WHERE ABS(i) < 7
)
SELECT TOP 1 @nextBusinessDate = DATEADD(day, i, @day)
FROM cte AS d1
INNER JOIN @businessDates AS d2 ON DATENAME(DW, DATEADD(day, i, @day)) = d2.WeekDay
WHERE d2.IsBusinessDate = 1
ORDER BY ABS(i)
-- Return the result of the function
RETURN @nextBusinessDate
END
将UDF的第二个版本与此测试数据一起使用:
DECLARE @type VARCHAR(10) = 'Next'
DECLARE @day DATE = '2014-12-22'
DECLARE @nextBusinessDate DATE
SET @nextBusinessDate = dbo.UDF_GetNextBusinessDay2(1,0,0,0,0,0,1, @type, @day)
SELECT @nextBusinessDate
产生以下结果:
2014-12-28
答案 2 :(得分:1)
此代码通过创建从开始日期开始的三个日期的列表来获取下一个或上一个工作日。如果我们想要上一个工作日,那么如果我们想要下一个工作日我们得到最小的日期,我们就会获得最大的约会。
DECLARE @direction AS INT =1
--If direction is 1 you get the next business day.
--If direction is -1 you get the previous business day.
DECLARE @startDate AS DATE ='2017-07-21'
SELECT CASE @direction WHEN 1 THEN MIN(listOfDays.d) ELSE MAX(listOfDays.d) END AS nextBusinessDay FROM(
(SELECT DATEADD(DAY,Number*@direction,@startDate)AS d FROM (VALUES (1),(2),(3)) AS Numbers(Number) )) listOfDays
WHERE DATEPART(WEEKDAY,listOfDays.d) NOT IN (1,7)
答案 3 :(得分:0)
以下代码从下周工作日的日期列表中选择,不包括周末和非工作日期。
要求:为了使以下代码正常工作,Numbers表必须存在,并且Non_working_dates表必须存在。
Numbers表应至少有一个字段。字段名称必须为Number。该字段不得接受重复。数据类型必须为INT。
Non_working_days表必须至少包含一个字段。字段名称必须为Non_working_date。该字段必须不接受重复值。数据类型必须是没有时间的DATE。
DECLARE @startDate AS DATE = '2017-07-03'
--Step 2. Get the next business day.
SELECT TOP 1 listOfDates.d AS nextBusinessDay FROM
(
--Step 1. Get a month's worth of dates.
The dates must not be weekend days or non working days.
SELECT DATEADD(DAY,Number,@startDate)AS d FROM Numbers WHERE Number < 30
) listOfDates
WHERE listOfDates.d> @startDate AND DATEPART(WEEKDAY,listofdates.d) NOT IN (1,7)
AND listOfDates.d NOT IN (SELECT Non_working_date FROM Non_working_dates WHERE Non_working_date>=@startDate)
ORDER BY listOfDates.d ASC