Home > OS >  Scalar function is non-deterministic
Scalar function is non-deterministic

Time:12-15

I'd like to persist this field but can't figure out why it's non-deterministic.

CREATE FUNCTION GetServiceMinutes
(
    -- Add the parameters for the function here
    @StartDate datetime,
    @EndDate datetime
)
RETURNS int WITH SCHEMABINDING
AS
BEGIN
    DECLARE @Result int

    SET @StartDate = CASE WHEN DATEPART(HOUR, @StartDate) < 8 THEN DATEADD(DAY, DATEDIFF(DAY, 0, @StartDate), '08:00:00')  ELSE @StartDate END
    SET @EndDate = CASE WHEN DATEPART(HOUR, @EndDate) >= 17 THEN DATEADD(DAY, DATEDIFF(DAY, 0, @EndDate), '17:00:00') ELSE @EndDate END
    
    SET @Result = 
         CASE WHEN DATEPART(DAY, @StartDate) != DATEPART(DAY, @EndDate) THEN 1000
              WHEN DATEPART(HOUR, @EndDate) < 8 THEN 0
              WHEN DATEPART(HOUR, @StartDate) >= 17 THEN 0
              ELSE DATEDIFF(MINUTE, @StartDate, @EndDate)
    END
    
    RETURN @Result

END
GO

This returns 0

SELECT OBJECTPROPERTY(OBJECT_ID('[dbo].GetServiceMinutes'), 'IsDeterministic')

Using SQL Server 2017

CodePudding user response:

The problem, as I alluded to, is your implicit conversions with (date and) time values. Per the documentation:

The following functions are not always deterministic, but can be used in indexed views or indexes on computed columns when they are specified in a deterministic manner.

Function Comments
all aggregate functions All aggregate functions are deterministic unless they are specified with the OVER and ORDER BY clauses. For a list of these functions, see Aggregate Functions (Transact-SQL).
CAST Deterministic unless used with datetime, smalldatetime, or sql_variant.
CONVERT Deterministic unless one of these conditions exists:
Source type is sql_variant.
Target type is sql_variant and its source type is nondeterministic.
Source or target type is datetime or smalldatetime, the other source or target type is a character string, and a nondeterministic style is specified. To be deterministic, the style parameter must be a constant. Additionally, styles less than or equal to 100 are nondeterministic, except for styles 20 and 21. Styles greater than 100 are deterministic, except for styles 106, 107, 109 and 113.

In your function you have implicit casting, for example '08:00:00' to a datetime. You need to be explicit:

CREATE FUNCTION dbo.GetServiceMinutes
(
    -- Add the parameters for the function here
    @StartDate datetime,
    @EndDate datetime
)
RETURNS int WITH SCHEMABINDING
AS
BEGIN
    DECLARE @Result int

    SET @StartDate = CASE WHEN DATEPART(HOUR, @StartDate) < 8 THEN DATEADD(DAY, DATEDIFF(DAY, 0, @StartDate), CONVERT(datetime,'1900-01-01T08:00:00',126))  ELSE @StartDate END
    SET @EndDate = CASE WHEN DATEPART(HOUR, @EndDate) >= 17 THEN DATEADD(DAY, DATEDIFF(DAY, 0, @EndDate), CONVERT(datetime,'1900-01-01T17:00:00',126)) ELSE @EndDate END
    
    SET @Result = 
         CASE WHEN DATEPART(DAY, @StartDate) != DATEPART(DAY, @EndDate) THEN 1000
              WHEN DATEPART(HOUR, @EndDate) < 8 THEN 0
              WHEN DATEPART(HOUR, @StartDate) >= 17 THEN 0
              ELSE DATEDIFF(MINUTE, @StartDate, @EndDate)
    END
    
    RETURN @Result

END
GO

SELECT OBJECTPROPERTY(OBJECT_ID('[dbo].GetServiceMinutes'), 'IsDeterministic')
  • Related