如何在 SQL 服务器中创建函数以将 2 个 datetime2 值与 GETDate 和 return 布尔值进行比较

How to create a function in SQL Server to compare 2 datetime2 values with GETDate and return a boolean

我想查询一个大的 table(超过 50k 行,+200 rows/day),在计算值上使用 where 条件。

在我的 table 中,我有 2 列包含 Shift(1 或 2 或 3)和一个日期(例如:2019-07-29 00:00:00.000);

我想 select 当前班次的所有行。

我想创建一个函数来计算班次开始日期时间和截止日期时间,然后比较 GETDATE() 是否介于两者之间,如果为真,则 return 行。

我尝试创建这个函数:

Create function IsCurrentShift(@shift int,@shiftDate DateTime)
returns bit
as
Begin
    Declare @result DateTime2,
     @hours int,
     @shiftStartDate DateTime2,
     @shiftDueDate DateTime2

 set @hours =   (CASE 
    when @shift = 1 then 6
    when @shift = 2 then 14 
    when @shift = 3 then 22 
    else 6
    end)

 set @shiftStartDate = DATEADD(hour,@hours,@shiftDate)
 set @shiftDueDate=DATEADD(hour,8,@shiftStartDate)

 if @shiftStartDate < GETDATE() and @shiftDueDate > GETDATE()
        set @result = 1
 else 
        set @result = 0

    Return @result
End

显然不是运行(我不知道如何修复)。

错误是:

Msg 206, Level 16, State 2, Procedure IsCurrentShift, Line 22 [Batch Start Line 0]
Operand type clash: int is incompatible with datetime2

Msg 206, Level 16, State 2, Procedure IsCurrentShift, Line 24 [Batch Start Line 0]
Operand type clash: int is incompatible with datetime2

我想这样调用这个函数:

Select * 
From tbl 
Where IsCurrentShift(shift, date) = 1;

我有两个问题:

  1. 有更好的方法来过滤我的 table?获取当前生产订单?

  2. 你能帮我修复这个功能吗?

我的 table 看起来像这样:

CREATE TABLE [dbo].[ProductionOrders]
(
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Date] [datetime] NOT NULL,
    [ShiftNumber] [int] NOT NULL,
    ...
) 

我想在视图中使用这个功能。

最好避免使用标量函数,除非您使用的是 SQL Server 2019,即便如此...

您可以将其直接写入您的查询,或者您可以创建一个内联 table 值函数来执行此操作(比标量函数性能更高)。

CREATE FUNCTION IsCurrentShift
    (@shift int, @shiftDate DateTime)
RETURNS TABLE WITH SCHEMABINDING
AS RETURN
(SELECT
    Result = CASE WHEN v2.shiftStartDate < GETDATE() and v2.shiftDueDate > GETDATE()
        THEN 1 ELSE 0 END
    FROM (SELECT hours = 
        CASE 
        when @shift = 1 then 6
        when @shift = 2 then 14 
        when @shift = 3 then 22 
        else 6
        end,
        ) v1
    CROSS APPLY (SELECT
        shiftStartDate = DATEADD(hour, v1.hours, @shiftDate),
        shiftDueDate =   DATEADD(hour,8 + v1.hours, @shiftDate)
    ) v2;

一个 table 值函数在逻辑上 return 每次被调用时都是一个整体 table (实际上它是内联的,速度快得多)。在这种情况下,我们只 returning 一个计算行。所以你可以在相关的子查询中使用它,像这样:

SELECT *
FROM tbl
WHERE (SELECT Result FROM IsCurrentShift(shift,date)) = 1;

或者您也可以 APPLY 结果。这会在结果集中为您提供一个新列:

SELECT *
FROM tbl
CROSS APPLY IsCurrentShift(shift,date) IsCurrent
WHERE IsCurrent.Result = 1;

您也可以将函数更改为实际 return 轮班开始和结束时间。

这是当前班次号码:

hour(dateadd(hour, -6, getdate())) / 8 + 1

向后调整六个小时(因为班次 1 从早上 6 点开始。)提取小时和整数除以八(所有班次的长度相等。)