使用SQLALTER函数更改列顺序会在依赖函数中产生奇怪的结果

使用SQLALTER函数更改列顺序会在依赖函数中产生奇怪的结果,sql,sql-server,Sql,Sql Server,似乎当您使用ALTER function修改函数的列顺序时,SQL不会更新依赖函数,并可能导致返回完全不正确的结果 是否有一种方法可以强制相关功能自动更新,而无需手动完成每一项功能 例如: create function dbo.Test1 () returns table AS return ( select 1 as [One], 2 as [Two] ) GO create function dbo.Test2 () returns table AS return (

似乎当您使用ALTER function修改函数的列顺序时,SQL不会更新依赖函数,并可能导致返回完全不正确的结果

是否有一种方法可以强制相关功能自动更新,而无需手动完成每一项功能

例如:

create function dbo.Test1 ()
returns table
AS
return
(
    select 1 as [One], 2 as [Two]   
)

GO

create function dbo.Test2 ()
returns table
AS
return
(
    select * from Test1()
)

GO
这些工作如预期的那样:

select * from Test1()
select * from Test2()
两者都返回:

One         Two
----------- -----------
1           2
现在,如果我们修改函数:

alter function dbo.Test1 ()
returns table
AS
return
(
    select 2 as [Two], 1 as [One]   
)

GO
并查询结果:

select * from Test1()
返回:

Two         One
----------- -----------
2           1
One         Two
----------- -----------
2           1
如预期,但:

select * from Test2()
返回:

Two         One
----------- -----------
2           1
One         Two
----------- -----------
2           1
所以,我们现在有了旧的列顺序,但值位于新的位置,这意味着本例中的值是转置的。

在处理UDF时,您需要使用sp_refreshsqlmodule。这将刷新元数据并返回正确的列

EXEC sp_refreshsqlmodule 'dbo.Test2'
sp_refreshsqlmodule将更新UDF的元数据。UDF的元数据(如参数或数据类型)可能会因为底层对象的更改而过时,这就是您的示例中发生的情况。我已经用你的例子对它进行了测试,它正按预期工作

有关sp_refershsqlmodule的更多信息,请参阅


正如Matthew Brophy指出的,正确的解决方案是在UDF中不使用SELECT*,而是显式地列出SELECT中的列名。

您的实际函数是否包含SELECT*?这将是一个坏主意。永远,永远,永远等等,在生产代码中使用SELECT*。这只是使用它引起的一个问题,还有其他问题。使用列名可以避免这个特殊的问题。为了更有趣,请尝试修改Test1以包含第三列。您将看到,Test2中的SELECT*仍然只返回两列。为了获得最大的乐趣,删除一个列-您现在将看到一个错误,说明视图或函数“Test2”指定的列名多于定义的列。这个故事的寓意是:不要在一般情况下使用SELECT*,尤其是在函数和视图中。这确实有效。不幸的是,对于所有依赖函数,它仍然需要手动干预,因此虽然有帮助,但并不完美。我认为真正的答案是明确列出列名。看起来不错,+1。还有,@MatthewBrophy,这就是野兽的本性;-。如果希望实现自动化,请创建DDL触发器以捕获ALTER FUNCTION事件,然后使用sys.sql_依赖项和sys.sql_表达式_依赖项查找任何依赖对象,并对找到的对象调用sp_refreshsqlmodule。当然,不使用SELECT*几乎总是一个好办法,但是在删除字段的情况下它会有帮助吗?@srutzky:然后别忘了为表和视图添加触发器,以防它们被SELECT*引用。。。那就是疯狂。我的意思是,你可以让它工作,但疯狂。我想说,如果您想要自动化,请使用sys.sql_modulesdefinition检查SELECT*的每个实例,并在源代码处修复它:-@Jeroenmoster你抢先发表评论,因为我更新了之前的评论,超过了5分钟的限制。我在澄清,我不是在反对摆脱SELECT*;我非常同意,99.5%的时间是纯e-v-I-l。我只是说,我不认为单凭这一点就可以避免使用sp_refreshsqlmodule甚至sp_refreshview。