当更改一个用户函数时,其他用户函数不会 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) 直到它也被 ALTER
ed。
我非常清楚如何解决这个问题(指定 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';
或者您可以使用 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 *
。
我有两个用户函数,一个调用另一个。
其中第一个被定义为
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) 直到它也被 ALTER
ed。
我非常清楚如何解决这个问题(指定 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';
或者您可以使用 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 *
。