开发者

Is there any way to make this UDF deterministic?

I assume this is not deterministic simply because DB_NAME() is not deterministic? If DB_NAME() is not deterministic, why is it not deterministic?

ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] ()
RETURNS bit
    WITH SCHEMABINDING
AS 
    BEGIN
        RETURN CASE WHEN DB_NAME() = 'PRODUCTION' THEN CONVERT(bit, 1) ELSE CONVERT(bit, 0) END
    END

Update: This version works, is deterministic, allows the same code to be used in any database and removes the hardcoding of the database name (which also allows me to remove another automatic system health exception about database name coding)

ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] ()
RETURNS bit
    WITH SCHEMABINDING
AS 
    BEGIN
        RETURN开发者_开发百科 (SELECT IS_PRODUCTION FROM TheSchema.IS_PRODUCTION)
    END

FYI This is the code snippet in my system health self-reporting system which I use to monitor potential problems.

    SELECT  'Non-deterministic Scalar UDF' AS Problem
           ,QUOTENAME(ROUTINE_SCHEMA) + '.' + QUOTENAME(ROUTINE_NAME) AS ROUTINE_NAME
    FROM    INFORMATION_SCHEMA.ROUTINES WITH (NOLOCK)
    WHERE   IS_DETERMINISTIC = 'NO'
            AND ROUTINE_TYPE = 'FUNCTION'
            AND DATA_TYPE <> 'TABLE'
    ORDER BY ROUTINE_SCHEMA
           ,ROUTINE_NAME


Sure, I can think of one way to make it deterministic. Deploy this function on your production database:

ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] ()
RETURNS bit
    WITH SCHEMABINDING
AS 
BEGIN
    RETURN CONVERT(bit, 1)
END

And deploy this one to your test database:

ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] ()
RETURNS bit
    WITH SCHEMABINDING
AS 
BEGIN
    RETURN CONVERT(bit, 0)
END

This may seem silly but IMO the database name should not be "hard coded" any more so than the return value of some UDF.

Better yet, just put this information in a configuration table somewhere.


Couldn't you maybe rewrite your function not to determine the DB_NAME() internally, but get it send in as a parameter??

ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] (DatabaseName VARCHAR(255))
RETURNS bit
WITH SCHEMABINDING
AS 
    BEGIN
        RETURN CASE WHEN DatabaseName = 'PRODUCTION' 
                    THEN CONVERT(bit, 1) 
                    ELSE CONVERT(bit, 0) 
               END
    END

Not it should be deterministic, right?

When you call it, you can use DB_NAME() as a function to determine the database name


A deterministic function, by definition, is a function whose return value is uniquely identified by the values of its agruments.

Now, given the arguments to DB_NAME() (which are none), can you tell what will it return?


In strictess sense of determinism, the result is not based on the input parameters, but on the state of an external object that is not within your control.

The name could be altered etc,

Alter Database Modify Name = new_name

On 2005, SQL doesn't prevent the function being created though when I tried it against the default schema. If you get into a situation where it refuses to accept a function based on non-determinism and you have to work around it (with the risks etc), the route around it is to create a view that uses the function, and then select from the view within the function.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜