在SQL Server中更改用户定义的表类型


Answers:


69

据我所知,不可能更改/修改表类型。您可以使用其他名称创建该类型,然后删除旧类型并将其修改为新名称。

jkrajes

按照msdn,就像“创建后无法修改用户定义的表类型定义”。


2
我根据用户定义的类型以及用户定义的类型本身使用一系列生成的所有对象的放置/创建脚本。
罗尼·欧弗比

6
如何在sql中以2​​0,000+行脚本结束?删除/创建需要更改的表类型的所有依赖项。:P
Spacemonkey 2015年

14
这很糟糕(Microsoft),现在每当我对这些表进行更改时,我都必须修改所有sp,然后删除,重新创建并返回并更新对它们的任何引用。想得很差..我知道这是一头胡话,但是他们在想什么呢?
schmoopy

1
同样,您似乎甚至都不允许更改用户定义表类型的所有者。删除表类型并使用新的所有者名称重新创建它似乎是更改所有者名称的唯一方法,以防您需要进行修改。sp_changeobjectowner不适用于用户定义的表类型...
Jeff

38

这是一种破解,但似乎确实可行。以下是修改表类型的步骤和示例。请注意,如果您对表类型所做的更改是对该对象(通常是过程)的重大更改,则sp_refreshsqlmodule将失败。

  1. 使用sp_rename重命名表的类型,我通常只是添加Z到名字的开头。
  2. 创建一个具有原始名称的新表类型,并对表类型进行任何修改。
  3. 逐步遍历每个依赖项并sp_refreshsqlmodule对其进行处理。
  4. 删除重命名的表类型。

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

警告:

这可能会对您的数据库造成破坏,因此您首先要在开发环境上进行测试。


在MSDN链接上对sp_refreshsqlmodule的说明:msdn.microsoft.com/en-us/library/bb326754.aspx很有威胁性。但是此SP是否还会更新引用对象的文本,或者只是更新那里的编译形式。我的意思是,如果我将在引用的SP之一上运行SP_HELPTEXT,那么我会在那里获得新的Type名称吗?
瑜伽士

这不会将您存储的proc中的表类型更改为z表类型。它所做的所有事情都会照原样刷新架构,但会将引用固定为您的表类型。如果sp_refreshsqlmodle在重新创建表类型后未在存储过程上运行,则存储的过程将失败,说明表类型已更改。我确实建议在生产环境中运行它之前,在您的数据库的开发版本上运行它。
诺兰多

1
这个答案对我不起作用。一旦执行了sp_rename,SP上的参数类型就会更新为引用新的UDTT。然后,以后不能删除重命名的UDTT。sp_rename强制执行依赖关系。该答案假定sp_rename不会在引用SP时更新参数类型。
murtazat 2015年

sp_rename在用户定义的datat类型上抛出一个错误:Either the parameter @objname is ambiguous or the claimed @objtype ((null)) is wrong.可能是什么错误?
Muflix '16

1
@Muflix,您可能需要传入这样的对象类型EXEC sys.sp_rename 'dbo.MyTableType', 'zMyTableType', 'OBJECT';。另外,请确保您要为第一个参数而不是第二个参数包含模式。
norlando

15

这是一些简单的步骤,可以最大程度地减少繁琐的工作,并且不需要容易出错的半自动化脚本或昂贵的工具。

请记住,您可以从“对象资源管理器详细信息”窗口为多个对象生成DROP / CREATE语句(以这种方式生成时,会将DROP和CREATE脚本进行分组,这使得在Drop和Create操作之间插入逻辑变得容易):

拖放并创建到

  1. 备份数据库,以防万一发生问题!
  2. 自动为所有依赖项生成DROP / CREATE语句(或为所有“可编程性”对象生成以消除查找依赖项的繁琐工作)。
  3. 在DROP和CREATE [dependencies]语句之间(在所有DROP之后,在所有CREATE之前),插入生成的DROP / CREATE [table type]语句,使用CREATE TYPE进行所需的更改。
  4. 运行脚本,该脚本将删除所有依赖项/ UDTT,然后重新创建[具有更改的UDTT] /依赖项。

如果您的小型项目可能需要更改基础架构,则请考虑消除用户定义的表类型。实体框架和类似的工具使您能够将大部分(如果不是全部)数据逻辑移至易于维护的代码库中。


1
我听取了您的建议,并考虑了迁移数十万行代码以使用Entity Framework,因此我们可以避免不得不删除并重新创建用户定义的表类型。但是,在一秒钟之后,我决定删除并重新创建表类型是目前更容易解决的问题。
PapillonUK

1
@PapillonUK,我和你在一起。我有一个较大的项目,所以我仍在做出与您相同的决定(而且上述方法是如此之快,以至于在可预见的将来我可能会继续这样做)。我提到了对于那些规模较小的项目,从UDTT移开,现在可以更改体系结构以简化将来的更改,因此,我相应地更新了答案。谢谢。
lightmotive

9

如果可以在Visual Studio中使用数据库项目,则可以在项目中进行更改,并使用架构比较将更改同步到数据库。

这样,更改脚本将处理删除并重新创建相关对象的过程。


我发现此答案与BioEcoSS的答案一起很有帮助
Padmika '19

8

Simon Zeinstra找到了解决方案!

但是,我使用了Visual Studio community 2015,甚至没有使用架构比较。

使用SQL Server Object Explorer,我在数据库中找到了用户定义的表类型。我右键单击表格类型,然后选择。这在IDE中打开了一个代码选项卡,其中TSQL代码可见且可编辑。我只是简单地更改了定义(在我的情况下,只是增加了nvarchar字段的大小),然后单击“更新数据库”了选项卡左上角的“按钮。

嗨,普雷斯托!-快速检查SSMS并修改了udtt定义。

辉煌-感谢Simon。


1
这可能更适合作为对答案的注释,而不是本身的答案。
菲尔·库珀

TBH我发现这非常有用,对我来说是解决此问题的简便方法,并向像我这样对Visual Studio中的数据库项目不太熟悉的人介绍了如何做。
Steve Kennaird '18

我也觉得这个答案很有帮助
Padmika '19

感谢您分享此= D
Ayorus

4

您应该删除旧表类型并创建一个新表类型。但是,如果它具有任何依赖项(任何使用它的存储过程),您将无法删除它。我已经发布了另一个答案,该答案是关于如何自动化临时删除所有存储过程,修改表表,然后还原存储过程的过程。


是否一定要具有依赖关系,否则为什么要创建它呢?
拉里

@LarryBud -一个简单的例子是,如果有人只是创造了它,并没有有机会尚未在任何存储过程等,使用它
BornToCode

3

您不能更改/修改您的类型。您必须删除现有文件,然后使用正确的名称/数据类型重新创建它,或添加一个新的列

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.