我如何在SQL Server中修改用户定义的表类型?
我如何在SQL Server中修改用户定义的表类型?
这种方法有点取巧,但似乎可行。以下是修改表类型的步骤和示例。需要注意的是,如果您对表类型所做的更改是破坏该对象(通常是过程)的更改,则sp_refreshsqlmodule
将失败。
sp_rename
重命名表类型,我通常只在名称前面添加z。sp_refreshsqlmodule
。EXEC sys.sp_rename 'dbo.MyTableType', 'zMyTableType';
GO
CREATE TYPE dbo.MyTableType AS TABLE(
Id INT NOT NULL,
Name VARCHAR(255) NOT NULL
);
GO
DECLARE @Name NVARCHAR(776);
DECLARE REF_CURSOR CURSOR FOR
SELECT referencing_schema_name + '.' + referencing_entity_name
FROM sys.dm_sql_referencing_entities('dbo.MyTableType', 'TYPE');
OPEN REF_CURSOR;
FETCH NEXT FROM REF_CURSOR INTO @Name;
WHILE (@@FETCH_STATUS = 0)
BEGIN
EXEC sys.sp_refreshsqlmodule @name = @Name;
FETCH NEXT FROM REF_CURSOR INTO @Name;
END;
CLOSE REF_CURSOR;
DEALLOCATE REF_CURSOR;
GO
DROP TYPE dbo.zMyTableType;
GO
警告:
这可能会破坏你的数据库,因此你应该先在开发环境中进行测试。
sp_refreshsqlmodle
,则存储过程将失败并显示表类型已更改。我建议在生产环境之前在开发版本的数据库上运行此操作。 - Nick Osp_rename
重命名用户定义的数据类型时,会抛出错误:参数 @objname 不明确或声明的 @objtype ((null)) 错误。
可能出了什么问题? - MuflixEXEC sys.sp_rename 'dbo.MyTableType','zMyTableType','OBJECT';
。此外,请确保第一个参数中包含模式,而第二个参数不包含。 - Nick OSimon Zeinstra找到了解决方案!
不过,我使用的是Visual Studio Community 2015,甚至都没有使用Schema Compare。
通过使用SQL Server Object Explorer,我在数据库中找到了我的用户定义表类型。我右键点击表格类型并选择 "xxxxx"。这打开了一个代码选项卡,在IDE中可见TSQL代码并且可以 编辑 。 我只需更改定义(在我的情况下只是增加了nvarchar字段的大小),然后单击选项卡左上角的Update Database按钮即可。
嘿,太棒了! - 在SSMS中快速检查,udtt定义已经被修改。
太棒了-谢谢Simon。
您需要删除旧表类型并创建新表。但是,如果有任何依赖项(任何使用它的存储过程),您将无法删除它。我在这里发布了另一个答案,介绍了如何自动删除所有存储过程、修改表格并恢复存储过程的过程。
你不能修改已有的数据类型,必须删除现有的类型并使用正确的名称/数据类型重新创建它,或者添加一个新的列。
我在项目中不得不对用户定义的表类型进行更改,以下是我采用的步骤:
create or ALTER proc create_or_alter_udt_postprocess(@udt_postprocess_data xml)
as
begin
if @udt_postprocess_data is null
return;
declare @obj_cursor cursor
set @obj_cursor = cursor fast_forward for
select n.c.value('.', 'nvarchar(max)') as definition
from @udt_postprocess_data.nodes('/Objects/definition') as n(c)
open @obj_cursor;
declare @definition nvarchar(max);
fetch next from @obj_cursor into @definition;
while (@@fetch_status = 0)
begin
exec sp_executesql @stmt= @definition
fetch next from @obj_cursor into @definition
end
CLOSE @obj_cursor;
DEALLOCATE @obj_cursor;
end
Create or ALTER proc create_or_alter_udt_preprocess(@udt nvarchar(200), @udt_postprocess_data xml out)
AS
BEGIN
set @udt_postprocess_data = null;
if TYPE_ID(@udt) is null
return;
declare @drop_scripts nvarchar(max);
SELECT @drop_scripts = (
(select N';'+ drop_script
from
(
SELECT
drop_script = N'drop ' + case sys.objects.type when 'P' then N'proc ' else N'function' end
+ sys.objects.name + N';' + + nchar(10) + nchar(13)
FROM sys.sql_expression_dependencies d
JOIN sys.sql_modules m ON m.object_id = d.referencing_id
JOIN sys.objects ON sys.objects.object_id = m.object_id
WHERE referenced_id = TYPE_ID(@udt)
) dependencies
FOR XML PATH (''), type
).value('.', 'nvarchar(max)')
) ;
declare @postprocess_data xml;
set @udt_postprocess_data =
(SELECT
definition
FROM sys.sql_expression_dependencies d
JOIN sys.sql_modules m ON m.object_id = d.referencing_id
JOIN sys.objects ON sys.objects.object_id = m.object_id
WHERE referenced_id = TYPE_ID(@udt)
FOR XML PATH (''), root('Objects'));
exec sp_executesql @stmt= @drop_scripts;
exec sp_droptype @udt;
END
使用示例:
begin tran
declare @udt_postprocess_data xml;
exec create_or_alter_udt_preprocess @udt= 'test_list', @udt_postprocess_data = @udt_postprocess_data out;
CREATE TYPE test_list AS TABLE(
test_name nvarchar(50) NULL
);
exec create_or_alter_udt_postprocess @udt_postprocess_data = @udt_postprocess_data;
commit;
设置示例使用的代码:
CREATE TABLE [dbo].[test_table](
[test_id] [int] IDENTITY(1,1) NOT NULL, [test_name] [varchar](20) NULL
) ON [USERDATA]
GO
CREATE TYPE test_list AS TABLE(test_name nvarchar(20) NULL)
GO
create proc add_tests(
@test_list test_list readonly)
as
begin
SET NOCOUNT ON;
insert into test_table(test_name)
select test_name
from @test_list;
end;
create proc add_tests2(
@test_list test_list readonly)
as
begin
SET NOCOUNT ON;
insert into test_table(test_name)
select test_name
from @test_list;
end;