I want to make a UDF which returns an integer form of YYYYMM
so that I can easily partition some things on month. I am trying to assign this function to the value of a PERSISTED
computed column.
I currently have the following, which works fine:
CREATE FUNCTION dbo.GetYearMonth(@pDate DATETIME2)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
DECLARE @fYear VARCHAR(4) = RIGHT('0000' + CAST(YEAR(@pDate) AS VARCHAR),4)
DECLARE @fMonth VARCHAR(2) = RIGHT('00' + CAST(MONTH(@pDate) AS VARCHAR),2)
RETURN CAST(@fYear + @fMonth AS INT)
END
But I think it's cleaner to use FORMAT
instead. I tried this:
CREATE FUNCTION dbo.GetYearMonth(@pDate DATETIME2)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
DECLARE @fYear VARCHAR(4) = FORMAT(@pDate,'yyyy', 'en-us')
DECLARE @fMonth VARCHAR(2) = FORMAT(@pDate,'MM', 'en-us')
RETURN CAST(@fYear + @fMonth AS INT)
END
But this function is nondeterministic.
Is there a way to make FORMAT
deterministic? Or is there a better way to do this, making the UDF deterministic?
Interesting question so I did some digging and came up with nothing conclusive :)
Starting with Deterministic and Nondeterministic Functions
which doesn't explicitly list
FORMAT
but states:and links to String Functions
Again, this page states
However, the page on
FORMAT
is silent on the subject.FORMAT
uses the CLR which doesn't preclude it from being deterministic but the doco is silent as to the actual implementation ofFORMAT
.Finally, suspecting this is a bug in the doco (or the code) a quick search of connect reveals nothing.
How about a test case? (Comments welcome on the validity of this code…)
Nup, that's nondeterministic.
So, an interesting exercise but nothing conclusive.
So what did we learn (according to BOL)? If a built-in function is nondeterministic, there's no way of making it so. Some are both depending on the parameter types, and some are supposed to be but aren't.
Microsoft isn't very clear about the format function being able to be determinstic. I couldn't find any info on the subject in its documentation. Being a CLR function i guess the awnser is it is not possible.
An even more simple solution to get an integer formatted the way you want would be:
I'm wondering why you are using a function. You can use a simple formula: