【问题标题】:When one user function is altered, other user function doesn't return correct data当一个用户函数被改变时,另一个用户函数不会返回正确的数据
【发布时间】:2015-12-01 18:39:54
【问题描述】:

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

首先定义为

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

另一个是从第一个中选择的:

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),第二个函数仍然保持不变并且只返回原始列(即它完全忽略D列)直到它是ALTER编辑也是如此。

我非常清楚如何解决这个问题(指定 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

【问题讨论】:

  • 顺便说一句,当视图被创建为select * ... 时会看到相同的行为。向基础表添加列不会向视图添加列。
  • 感觉就像创建或修改一个调用另一个函数的函数会创建第一个函数使用的字段列表。在更新调用函数之前,此字段列表似乎不会更改。我也想知道为什么。

标签: sql sql-server tsql sql-server-2012 user-defined-functions


【解决方案1】:

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

更新指定的非模式绑定存储的元数据 过程、用户定义函数、视图、DML 触发器、数据库级 DDL 触发器,或当前数据库中的服务器级 DDL 触发器。 这些对象的持久元数据,例如 参数,可能会因为其基础的变化而变得过时 对象。

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:

如果用户定义的函数不是使用 SCHEMABINDING 创建的 子句中,对基础对象所做的更改可能会影响 定义函数并在执行时产生意想不到的结果 调用。我们建议您实现以下方法之一 确保函数不会因为以下原因而过时 对其底层对象的更改:

1) 在创建函数时指定WITH SCHEMABINDING 子句。这样可以确保函数中引用的对象 除非函数也被修改,否则不能修改定义。

2) 修改函数定义中指定的任何对象后,执行sp_refreshsqlmodule 存储过程。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多