Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I make SQL Server FORMAT deterministic?

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?

like image 824
Matthew Avatar asked Dec 11 '22 16:12

Matthew


1 Answers

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:

All of the aggregate and string built-in functions are deterministic.

and links to String Functions

Again, this page states

All built-in string functions are deterministic. This means they return the same value any time they are called with a specific set of input values.

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 of FORMAT.

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…)

CREATE FUNCTION WhatAmI(@Number INTEGER) 
RETURNS NVARCHAR
WITH SCHEMABINDING
AS 
BEGIN
RETURN FORMAT(@Number, 'd')
END
GO

SELECT OBJECTPROPERTY(OBJECT_ID('WhatAmI'),'IsDeterministic')

-----------
0

(1 row(s) affected)

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.

like image 55
Liesel Avatar answered Jan 15 '23 12:01

Liesel