你能告诉SQL Server你不关心函数是否被公式引用,并让它去更改底层函数吗?
额外细节:计算列不是持久化的,也没有被FK约束引用,因为它是不确定的。该函数考虑了当前时间。它处理的是记录是否过期的问题。
非常抱歉回复晚了,但这个答案可能会有用。
您可以为每个计算列使用一个虚拟函数来调用您的真实函数。
例如:
计算列使用公式:dbo.link_comp('123')
此函数转发参数并调用并返回函数 dbo.link('123')(您的真实函数)
两个函数只需要使用相同的参数并返回相同的类型即可。
然后,被锁定的函数是dbo.link_comp,您仍然可以更改dbo.link。
此外,如果您的函数从其他SQL中调用,则仍然可以使用您的真实函数名称dbo.link,虚拟函数dbo.link_comp仅用于计算列。
ALTER操作的后果可能是巨大的。
您是否已经为列创建索引?在具有模式绑定的视图中使用了它?保存了它?与之有外键关系?
如果ALTER更改了数据类型、NULLability或确定性,会怎样呢?
停止具有依赖关系的ALTER FUNCTION比处理这么多情况要容易得多。
我知道现在有点晚了,但今天我也遇到了同样的问题,而且没有找到任何能够真正解决问题的东西,所以我很快地写了一个脚本。
它基本上创建一个临时表,使用函数来保存每个计算列的列信息,然后从表中删除这些列。然后你可以更新你的函数,并让它再次创建所有的列和它们的定义。
如果你需要更改定义中的参数(就像我需要的那样),你可以简单地将这部分脚本放入重新创建定义的位置。
如果你的索引或其他需求中有计算列,你可以很容易地扩展代码,但这超出了我的需求范围。
希望对其他人有用。
/* Create temporary table to hold definitions */
CREATE TABLE [#FUNCTION]
(
[TABLE_NAME] nvarchar(255) NOT NULL,
[COLUMN_NAME] nvarchar(255) NOT NULL,
[DEFINITION] nvarchar(255) NOT NULL
)
GO
/* Add data to temp table */
INSERT INTO [#FUNCTION] ( [TABLE_NAME], [COLUMN_NAME], [DEFINITION] )
SELECT TABLE_NAME, COLUMN_NAME, definition FROM INFORMATION_SCHEMA.COLUMNS
INNER JOIN sys.computed_columns ON ( object_id = object_id( TABLE_NAME ) AND name = COLUMN_NAME )
WHERE definition LIKE '%MyFunctionName%'
GO
/* Remove columns */
DECLARE @TABLE_NAME nvarchar(255)
DECLARE @COLUMN_NAME nvarchar(255)
DECLARE c_CursorName CURSOR LOCAL FOR SELECT [TABLE_NAME], [COLUMN_NAME] FROM [#FUNCTION]
OPEN c_CursorName
FETCH NEXT FROM c_CursorName INTO @TABLE_NAME, @COLUMN_NAME
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC( 'ALTER TABLE [' + @TABLE_NAME + '] DROP COLUMN [' + @COLUMN_NAME + ']' )
FETCH NEXT FROM c_CursorName INTO @TABLE_NAME, @COLUMN_NAME
END
CLOSE c_CursorName
DEALLOCATE c_CursorName
GO
/* Update function */
-- Update function here
GO
/* Recreate computed columns */
DECLARE @TABLE_NAME nvarchar(255)
DECLARE @COLUMN_NAME nvarchar(255)
DECLARE @DEFINITION nvarchar(255)
DECLARE c_CursorName CURSOR LOCAL FOR SELECT [TABLE_NAME], [COLUMN_NAME], [DEFINITION] FROM [#FUNCTION]
OPEN c_CursorName
FETCH NEXT FROM c_CursorName INTO @TABLE_NAME, @COLUMN_NAME, @DEFINITION
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC( 'ALTER TABLE [' + @TABLE_NAME + '] ADD [' + @COLUMN_NAME + '] AS ' + @DEFINITION )
FETCH NEXT FROM c_CursorName INTO @TABLE_NAME, @COLUMN_NAME, @DEFINITION
END
CLOSE c_CursorName
DEALLOCATE c_CursorName
GO
/* Remove temp table */
DROP TABLE [#FUNCTION]
GO
Select C1, C2, C3, C5 into TmpT1 from T1
Go
Delete From T1
go
现在您可以修改C4列
Alter table T1 alter column C4 as dbo.NewFunc()
Go
Insert Into T1 (C1,C2,C3,C5) select C1,C2,C3,C5 from TmpT1
现在删除临时表
Drop Table TmpT1
你可以将该列更改为非计算列,并通过TRIGGER进行更新。
或者,您可以将表重命名为其他名称,删除计算列,并创建一个视图来代替原始表(即使用原始表名称),并包括您需要的“计算”列。
编辑:请注意,这可能会影响您插入到原始表名称(现在是视图)中的操作。显然,您可以保留旧表,删除计算列,并创建一个单独的视图,其中包含计算列。
我们不得不解决计算列的问题很多次,以至于我们已经决定它们带来的麻烦比收益还要多。安全插入(1),尝试插入到具有计算列的表上的视图,需要处理SET ARITHABORT等问题。
(1)我们有像下面这样的安全插入:
INSERT INTO MyTable SELECT * FROM MyOtherTable WHERE ...
如果在一个表中添加了新列而另一个表没有,则设计为失败。对于计算列,我们必须明确命名所有列,这使我们失去了这个安全网。