SQL 工作日函数

SQL working days function

我正在尝试计算前 5 个工作日,如果是周六或周日,则需要使用周五作为最后一个工作日。

我得到了这个查询的 if else 部分,但是当我尝试使用它来创建一个函数时,我收到了错误消息,我错过了什么想法?

create table holidays  (
  date date);
GO



create function dbo.WorkDays
(

@date datetime, 
@days int

)

returns date 

as

Begin

IF datename(dw,@date) = 'Saturday' 

select dateadd(dd,-1,thedate)
  from (
  select thedate=dateadd(d,-v.day,cast(@date as date)),
         rn=row_number() over (order by v.day),
         weekday = datename(dw,dateadd(d,-v.day,cast(@date as date)))
  from (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10))v(day)
  left join holidays h on h.date = dateadd(d,v.day,cast(@date as date))
  where left(datename(dw,dateadd(d,-v.day,cast(@date as date))),1) <> 'S'
  ) x
  where @days = rn

Else If datename(dw,@date) = 'Sunday'

select dateadd(dd,-1,thedate)
  from (
  select thedate=dateadd(d,-v.day,cast(@date as date)),
         rn=row_number() over (order by v.day),
         weekday = datename(dw,dateadd(d,-v.day,cast(@date as date)))
  from (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10))v(day)
  left join holidays h on h.date = dateadd(d,v.day,cast(@date as date))
  where left(datename(dw,dateadd(d,-v.day,cast(@date as date))),1) <> 'S'
  ) x
  where @days = rn

Else

select thedate
  from (
  select thedate=dateadd(d,-v.day,cast(@date as date)),
         rn=row_number() over (order by v.day),
         weekday = datename(dw,dateadd(d,-v.day,cast(@date as date)))
  from (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10))v(day)
  left join holidays h on h.date = dateadd(d,v.day,cast(@date as date))
  where left(datename(dw,dateadd(d,-v.day,cast(@date as date))),1) <> 'S'
  ) x
  where @days = rn

End 

drop table holidays

显示的错误是: Select 包含在函数中的语句不能 return 数据到客户端。

您需要声明一个@return变量,并将每个select语句的输出赋值给它:

create function dbo.WorkDays
(

@date datetime, 
@days int

)

returns date 

as

Begin
DECLARE @return date

IF datename(dw,@date) = 'Saturday' 

select @return = dateadd(dd,-1,thedate)
  from (
  select thedate=dateadd(d,-v.day,cast(@date as date)),
         rn=row_number() over (order by v.day),
         weekday = datename(dw,dateadd(d,-v.day,cast(@date as date)))
  from (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10))v(day)
  left join holidays h on h.date = dateadd(d,v.day,cast(@date as date))
  where left(datename(dw,dateadd(d,-v.day,cast(@date as date))),1) <> 'S'
  ) x
  where @days = rn

Else If datename(dw,@date) = 'Sunday'

select @return = dateadd(dd,-1,thedate)
  from (
  select thedate=dateadd(d,-v.day,cast(@date as date)),
         rn=row_number() over (order by v.day),
         weekday = datename(dw,dateadd(d,-v.day,cast(@date as date)))
  from (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10))v(day)
  left join holidays h on h.date = dateadd(d,v.day,cast(@date as date))
  where left(datename(dw,dateadd(d,-v.day,cast(@date as date))),1) <> 'S'
  ) x
  where @days = rn

Else

select @return= thedate
  from (
  select thedate=dateadd(d,-v.day,cast(@date as date)),
         rn=row_number() over (order by v.day),
         weekday = datename(dw,dateadd(d,-v.day,cast(@date as date)))
  from (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10))v(day)
  left join holidays h on h.date = dateadd(d,v.day,cast(@date as date))
  where left(datename(dw,dateadd(d,-v.day,cast(@date as date))),1) <> 'S'
  ) x
  where @days = rn


  return @return
End 

我想你的查询逻辑是正确的。

USE [DBName]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[fnGetWorkdays]
(
@f datetime=null,@t datetime=null

)
RETURNS int 
AS

BEGIN
 declare @retVal int=0

  set @retVal=( 
                  select count(DyName) as DayCnt
                    from  CalenderInfo where 
                    DteName between @f and @t  and DyName not in('Friday')
                    and DteName not in  
                    ( select Fromdate from  HolidayInfo where Fromdate between @f and @t  )

   )

 return @retVal


END

Table 1: 日历信息

DayID   int
DyName  varchar(20)
DteName datetime

Table 2: 假日信息

HolidayDetailsID    int
HolidayID   int
HolydayName varchar(100)
Fromdate    datetime
Todate  datetime
IsPublic    int
IsCalculated    int
IsInactive  int