当更改一个用户函数时,其他用户函数不会 return 更正数据

When one user function is altered, other user function doesn't return correct data

我有两个用户函数,一个调用另一个。

其中第一个被定义为

CREATE FUNCTION [dbo].[fnTest] (
@a INT
, @b INT
)
RETURNS @data TABLE (
    A varchar(20),
    B varchar(20),
    C varchar(20)
    )
AS BEGIN
        INSERT INTO @data
        SELECT 'A' A, 'B' B, 'C' C
   RETURN
END

另一个是第一个的普通 select:

CREATE FUNCTION [dbo].[fnTest2] (
    @a INT
    , @b INT
    , @c VARCHAR(20)
    ) RETURNS TABLE
    AS
    RETURN SELECT * FROM dbo.fnTest(@a, @b) WHERE C = @c

当我 ALTER 第一个函数,向结果添加一个新列(例如 D)时,第二个函数仍然没有改变并且 returns 只有原始列(即它完全忽略列D) 直到它也被 ALTERed。

我非常清楚如何解决这个问题(指定 Test2 中的所有列或通过 ALTER 命令重新创建 Test2),但我的问题是 - 为什么我需要这样做?是否有一些设置可以自动重建它?

郑重声明,我使用的 ALTER 查询是:

ALTER FUNCTION [dbo].[fnTest] (
    @a INT
    , @b INT
    )
RETURNS @data TABLE (
    A varchar(20),
    B varchar(20),
    C varchar(20),
    D varchar(20)
    )
AS BEGIN
        INSERT INTO @data
        SELECT 'A' A, 'B' B, 'C' C, 'D' D
    RETURN
END

您可以使用 sp_refreshsqlmodule 刷新元数据:

Updates the metadata for the specified non-schema-bound stored procedure, user-defined function, view, DML trigger, database-level DDL trigger, or server-level DDL trigger in the current database. Persistent metadata for these objects, such as data types of parameters, can become outdated because of changes to their underlying objects.

CREATE FUNCTION [dbo].[fnTest] (
@a INT
, @b INT
)
RETURNS @data TABLE (
    A varchar(20),
    B varchar(20),
    C varchar(20)
    )
AS BEGIN
        INSERT INTO @data
        SELECT 'A' A, 'B' B, 'C' C
   RETURN
END;
GO

CREATE FUNCTION [dbo].[fnTest2] (
    @a INT
    , @b INT
    , @c VARCHAR(20)
    ) RETURNS TABLE
    AS
    RETURN SELECT * FROM dbo.fnTest(@a, @b) WHERE C = @c
    GO

    ALTER FUNCTION [dbo].[fnTest] (
    @a INT
    , @b INT
    )
RETURNS @data TABLE (
    A varchar(20),
    B varchar(20),
    C varchar(20),
    D varchar(20)
    )
AS BEGIN
        INSERT INTO @data
        SELECT 'A' A, 'B' B, 'C' C, 'D' D
    RETURN
END
GO

EXEC sys.sp_refreshsqlmodule 'dbo.fnTest2';

SqlFiddleDemo

或者您可以使用 WITH SCHEMABINDING:

If a user-defined function is not created with the SCHEMABINDING clause, changes that are made to underlying objects can affect the definition of the function and produce unexpected results when it is invoked. We recommend that you implement one of the following methods to ensure that the function does not become outdated because of changes to its underlying objects:

1) Specify the WITH SCHEMABINDING clause when you are creating the function. This ensures that the objects referenced in the function definition cannot be modified unless the function is also modified.

2) Execute the sp_refreshsqlmodule stored procedure after modifying any object that is specified in the definition of the function.

请记住,使用 SCHEMABINDING 时不允许使用 SELECT *