如何在 SQL Server 中创建一个函数来将 2 个 datetime2 值与 GETDate 进行比较并返回一个布尔值

问题描述

我想用计算值的 where 条件查询一个大表(超过 50k 行,+200 行/天)。

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

我想从当前班次中选择所有行。

我想创建一个函数来计算轮班开始日期时间和到期日期时间,然后比较 GETDATE() 是否在两者之间,如果为真则返回行。

我尝试创建这个函数

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]
操作数类型冲突:int 与 datetime2 不兼容

Msg 206,Line 24 [Batch Start Line 0]
操作数类型冲突:int 与 datetime2 不兼容

这个函数我想这样调用

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

我有两个问题:

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

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

我的桌子是这样的:

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

我想在一个视图中使用这个函数

解决方法

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

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

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;

一个表值函数在每次被调用时逻辑上返回整个表(实际上它是内联的,快得多)。在这种情况下,我们只返回单个计算行。因此,您可以在相关子查询中使用它,如下所示:

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;

您还可以更改函数以实际返回班次开始和结束时间。

,

这是当前的班次编号:

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

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