Cannot persist computed column - not deterministic

24,627

CONVERT([varchar](4),@Year,(0))+'-01-01' is being passed to a DATEDIFF call, in a position where a date is expected, forcing an implicit conversion to occur.

From the rules for deterministic functions:

CAST

Deterministic unless used with datetime, smalldatetime, or sql_variant.

CONVERT

Deterministic unless one of these conditions exists:

...

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.

Well, you're calling neither, but you're relying on an implicit conversion, which I'd expect to act like CAST. Rather than rely on this, I'd switch to using CONVERT and give a deterministic style parameter.

So, I'd do: CONVERT(datetime,CONVERT([varchar](4),@Year,(0))+'0101',112) in its place. Having done so, the function itself becomes deterministic

Share:
24,627
sprocket12
Author by

sprocket12

Updated on January 03, 2020

Comments

  • sprocket12
    sprocket12 over 4 years

    I have this function for a computed column :

    CREATE FUNCTION [dbo].[GetAllocatedStartTime](@Year INT, @Week INT)
    RETURNS DATETIME
    
    WITH schemabinding
    AS BEGIN
        RETURN dateadd(week,@Week-(1),dateadd(day,(-1),dateadd(week,datediff(week,(0),CONVERT([varchar](4),@Year,(0))+'-01-01'),(1))))
    END
    
    GO
    

    I added the WITH schemabinding in the hope it would make it deterministic so I can persist it. It should be as the two inputs [Week] and [Year] will always yield the same results.

    The exact error is :

    Computed column 'AllocatedTimeStart' in table 'Tmp_Bookings' cannot be persisted because the column is non-deterministic.

    I am using this formula in the column :

    ([dbo].[GetAllocatedStartTime]([Year],[Week]))
    

    And the column defs :

    [Week] [int] NOT NULL,
    [Year] [int] NOT NULL,
    [AllocatedTimeStart]  AS ([dbo].[GetAllocatedStartTime]([Year],[Week])),
    

    Any ideas?

    EDIT:

    Changed line to :

    RETURN dateadd(week,@Week-(1),dateadd(day,(-1),dateadd(week,datediff(week,(0),CONVERT(datetime,CONVERT([varchar](4),@Year,(0))+'0101',112)),(1))))
    

    But now I get an error saying the formula for the column is invalid. Even though the function saves fine.

    EDIT 2:

    I've shown exactly what I am doing (or atleast I've tried). There is nothing extra really. As it says the previous function (original one) coupled with the formula ref [dbo].AllocatedStartDate(...) to it in the column worked, but was not persisting, it said it was non deterministic. So according to the suggestion I changed the FUNCTION, replacing the conversion part with the new code, so the function now looks like :

    FUNCTION [dbo].[GetSTime](@Year INT, @Week INT)
    
    RETURNS DATETIME
    WITH schemabinding
    AS BEGIN
        RETURN dateadd(week,@Week-(1),dateadd(day,(-1),dateadd(week,datediff(week,(0),CONVERT(datetime,CONVERT([varchar](4),@Year,(0))+'0101',112)),(1))))
    END
    

    Then I tried the same formula as before in the computed field (([dbo].[GetAllocatedStartTime]([Year],[Week]))) ... and it rejects the formula, says its not valid... which is strange as the formula is the same, so it must be doing some sort of check of the changed function and finding that to be invalid, which is also strange because I did a plain SELECT dbo.GetAllocatedStartTime(2012,13) and it worked...

    So yes I am confused, and I've never seen SqlFiddle never mind use it. But really there is nothing more than what I have just said.

  • ypercubeᵀᴹ
    ypercubeᵀᴹ over 11 years
    If on SQL-Server 2012, they could also use - instead of the CONVERT([varchar](4),@Year,(0))+'-01-01' - the DATEFROMPARTS([Year],1,1) function: SQL-Fiddle test
  • sprocket12
    sprocket12 over 11 years
    Hi there I tried to replace the part, but I hit another issue :/ please see edit above.