我在DB中创建了几个用户定义的类型,如下所示
CREATE TYPE [dbo].[StringID] FROM [nvarchar](20) NOT NULL
并分配到各种表格。我在db中的表格有各种模式(不仅仅是dbo)
但是我意识到我需要更大的字段,我需要改变,例如从nvarchar增加到nvarchar,但是没有ALTER TYPE语句
我需要一个临时表/游标的脚本,并保存所有使用我的类型的表和字段。然后将现有字段更改为基本类型 - 例如从CustID [StringID]到CustID [nvarchar(20)]。 删除用户类型并使用新类型重新创建 - 例如为nvarchar(50) 最后将字段设置为用户类型
我没有对类型定义规则,因此不必删除规则并重新添加它们
我对T-Sql不太熟悉,所以感谢任何帮助。
答案 0 :(得分:30)
这是我通常使用的,虽然有点手册:
/* Add a 'temporary' UDDT with the new definition */
exec sp_addtype t_myudt_tmp, 'numeric(18,5)', NULL
/* Build a command to alter all the existing columns - cut and
** paste the output, then run it */
select 'alter table dbo.' + TABLE_NAME +
' alter column ' + COLUMN_NAME + ' t_myudt_tmp'
from INFORMATION_SCHEMA.COLUMNS
where DOMAIN_NAME = 't_myudt'
/* Remove the old UDDT */
exec sp_droptype t_mydut
/* Rename the 'temporary' UDDT to the correct name */
exec sp_rename 't_myudt_tmp', 't_myudt', 'USERDATATYPE'
答案 1 :(得分:6)
我们正在使用以下程序,它允许我们从头开始重新创建一个类型,这是一个“开始”。它重命名现有类型,创建类型,重新编译存储过程,然后删除旧类型。这样可以解决由于引用该类型而导致简单地删除旧类型定义失败的情况。
用法示例:
exec RECREATE_TYPE @schema='dbo', @typ_nme='typ_foo', @sql='AS TABLE([bar] varchar(10) NOT NULL)'
代码:
CREATE PROCEDURE [dbo].[RECREATE_TYPE]
@schema VARCHAR(100), -- the schema name for the existing type
@typ_nme VARCHAR(128), -- the type-name (without schema name)
@sql VARCHAR(MAX) -- the SQL to create a type WITHOUT the "CREATE TYPE schema.typename" part
AS DECLARE
@scid BIGINT,
@typ_id BIGINT,
@temp_nme VARCHAR(1000),
@msg VARCHAR(200)
BEGIN
-- find the existing type by schema and name
SELECT @scid = [SCHEMA_ID] FROM sys.schemas WHERE UPPER(name) = UPPER(@schema);
IF (@scid IS NULL) BEGIN
SET @msg = 'Schema ''' + @schema + ''' not found.';
RAISERROR (@msg, 1, 0);
END;
SELECT @typ_id = system_type_id FROM sys.types WHERE UPPER(name) = UPPER(@typ_nme);
SET @temp_nme = @typ_nme + '_rcrt'; -- temporary name for the existing type
-- if the type-to-be-recreated actually exists, then rename it (give it a temporary name)
-- if it doesn't exist, then that's OK, too.
IF (@typ_id IS NOT NULL) BEGIN
exec sp_rename @objname=@typ_nme, @newname= @temp_nme, @objtype='USERDATATYPE'
END;
-- now create the new type
SET @sql = 'CREATE TYPE ' + @schema + '.' + @typ_nme + ' ' + @sql;
exec sp_sqlexec @sql;
-- if we are RE-creating a type (as opposed to just creating a brand-spanking-new type)...
IF (@typ_id IS NOT NULL) BEGIN
exec recompile_prog; -- then recompile all stored procs (that may have used the type)
exec sp_droptype @typename=@temp_nme; -- and drop the temporary type which is now no longer referenced
END;
END
GO
CREATE PROCEDURE [dbo].[recompile_prog]
AS
BEGIN
SET NOCOUNT ON;
DECLARE @v TABLE (RecID INT IDENTITY(1,1), spname sysname)
-- retrieve the list of stored procedures
INSERT INTO
@v(spname)
SELECT
'[' + s.[name] + '].[' + items.name + ']'
FROM
(SELECT sp.name, sp.schema_id, sp.is_ms_shipped FROM sys.procedures sp UNION SELECT so.name, so.SCHEMA_ID, so.is_ms_shipped FROM sys.objects so WHERE so.type_desc LIKE '%FUNCTION%') items
INNER JOIN sys.schemas s ON s.schema_id = items.schema_id
WHERE is_ms_shipped = 0;
-- counter variables
DECLARE @cnt INT, @Tot INT;
SELECT @cnt = 1;
SELECT @Tot = COUNT(*) FROM @v;
DECLARE @spname sysname
-- start the loop
WHILE @Cnt <= @Tot BEGIN
SELECT @spname = spname
FROM @v
WHERE RecID = @Cnt;
--PRINT 'refreshing...' + @spname
BEGIN TRY -- refresh the stored procedure
EXEC sp_refreshsqlmodule @spname
END TRY
BEGIN CATCH
PRINT 'Validation failed for : ' + @spname + ', Error:' + ERROR_MESSAGE();
END CATCH
SET @Cnt = @cnt + 1;
END;
END
答案 2 :(得分:5)
there's a good example of a more comprehensive script here
值得注意的是,如果您有任何视图,此脚本将包含视图。我运行它而不是exec'ing内联生成一个脚本作为输出,然后我调整并运行。
此外,如果你有使用用户拒绝类型的函数/ sprocs,你需要在运行脚本之前删除它们。
经验教训:将来,不要为UDT烦恼,他们比他们的价值更麻烦。
SET NOCOUNT ON
DECLARE @udt VARCHAR(150)
DECLARE @udtschema VARCHAR(150)
DECLARE @newudtschema VARCHAR(150)
DECLARE @newudtDataType VARCHAR(150)
DECLARE @newudtDataSize smallint
DECLARE @OtherParameter VARCHAR(50)
SET @udt = 'Name' -- Existing UDDT
SET @udtschema = 'dbo' -- Schema of the UDDT
SET @newudtDataType = 'varchar' -- Data type for te new UDDT
SET @newudtDataSize = 500 -- Lenght of the new UDDT
SET @newudtschema = 'dbo' -- Schema of the new UDDT
SET @OtherParameter = ' NULL' -- Other parameters like NULL , NOT NULL
DECLARE @Datatype VARCHAR(50),
@Datasize SMALLINT
DECLARE @varcharDataType VARCHAR(50)
DECLARE @Schemaname VARCHAR(50),
@TableName VARCHAR(50),
@FiledName VARCHAR(50)
CREATE TABLE #udtflds
(
Schemaname VARCHAR(50),
TableName VARCHAR(50),
FiledName VARCHAR(50)
)
SELECT TOP 1
@Datatype = Data_type,
@Datasize = character_maximum_length
FROM INFORMATION_SCHEMA.COLUMNS
WHERE Domain_name = @udt
AND Domain_schema = @udtschema
SET @varcharDataType = @Datatype
IF @DataType Like '%char%'
AND @Datasize IS NOT NULL
AND ( @newudtDataType <> 'varchar(max)'
OR @newudtDataType <> 'nvarchar(max)'
)
BEGIN
SET @varcharDataType = @varcharDataType + '('
+ CAST(@Datasize AS VARCHAR(50)) + ')'
END
INSERT INTO #udtflds
SELECT TABLE_SCHEMA,
TABLE_NAME,
Column_Name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE Domain_name = @udt
AND Domain_schema = @udtschema
DECLARE @exec VARCHAR(500)
DECLARE alter_cursor CURSOR
FOR SELECT Schemaname,
TableName,
FiledName
FROM #udtflds
OPEN alter_cursor
FETCH NEXT FROM alter_cursor INTO @Schemaname, @TableName, @FiledName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @exec = 'Alter Table ' + @Schemaname + '.' + @TableName
+ ' ALTER COLUMN ' + @FiledName + ' ' + @varcharDataType
EXECUTE ( @exec
)
FETCH NEXT FROM alter_cursor INTO @Schemaname, @TableName, @FiledName
END
CLOSE alter_cursor
SET @exec = 'DROP TYPE [' + @udtschema + '].[' + @udt + ']'
EXEC ( @exec
)
SET @varcharDataType = @newudtDataType
IF @newudtDataType Like '%char%'
AND @newudtDataSize IS NOT NULL
AND ( @newudtDataType <> 'varchar(max)'
OR @newudtDataType <> 'nvarchar(max)'
)
BEGIN
SET @varcharDataType = @varcharDataType + '('
+ CAST(@newudtDataSize AS VARCHAR(50)) + ')'
END
SET @exec = 'CREATE TYPE [' + @newudtschema + '].[' + @udt + '] FROM '
+ @varcharDataType + ' ' + @OtherParameter
EXEC ( @exec
)
OPEN alter_cursor
FETCH NEXT FROM alter_cursor INTO @Schemaname, @TableName, @FiledName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @exec = 'Alter Table ' + @Schemaname + '.' + @TableName
+ ' ALTER COLUMN ' + @FiledName + ' ' + '[' + @newudtschema
+ '].[' + @udt + ']'
EXECUTE ( @exec
)
FETCH NEXT FROM alter_cursor INTO @Schemaname, @TableName, @FiledName
END
CLOSE alter_cursor
DEALLOCATE alter_cursor
SELECT *
FROM #udtflds
DROP TABLE #udtflds
1:http://www.sql-server-performance.com/2008/how-to-alter-a-uddt/已取代http://www.sql-server-performance.com/faq/How_to_alter_a%20_UDDT_p1.aspx
答案 3 :(得分:4)
正如devio所说,如果UDT正在使用中,则无法简单地编辑UDT。
通过SMS为我工作的工作回合是生成一个创建脚本并进行适当的更改;重命名现有的UDT;运行创建脚本;重新编译相关的sprocs并删除重命名的版本。
答案 4 :(得分:3)
此处提供的解决方案仅在仅在表定义中使用用户定义类型且未对UDT列编制索引时才应用。
一些开发人员也使用UDT参数来获取SP和函数,这些参数也没有涉及。 (请参阅Robin's link和Connect entry)
中的评论2007年的Connect条目最终在3年后关闭:
感谢您提交此内容 建议,但优先考虑 相对于其他许多项目 我们的队列,我们不太可能 实际上完成它。因此,我们是 结束这个建议是“不会 修复”。
我试图解决类似的问题ALTERing XML SCHEMA COLLECTIONS,而且这些步骤似乎也主要适用于ALTER TYPE:
要删除UDT,必须执行以下步骤:
答案 5 :(得分:2)
旧问题的新答案:
Visual Studio数据库项目在部署更改时处理删除和重新创建过程。它将删除使用UDDT的存储过程,然后在删除并重新创建数据类型后重新创建它们。
答案 6 :(得分:1)
最简单的方法是通过Visual Studio的对象资源管理器,社区版也支持它。
一旦你有made a connection到SQL服务器,浏览到该类型,右键单击并选择查看代码,对用户定义类型的模式进行更改,然后单击更新。 Visual Studio应该向您显示该对象的所有依赖项,并生成脚本以更新类型并重新编译依赖项。
答案 7 :(得分:0)
1.重命名旧UDT,
2.执行查询,
3.弃掉旧的UDT。
答案 8 :(得分:0)
我在存储过程中遇到了自定义类型的问题,并使用下面的脚本解决了这个问题。我不完全理解上面的脚本,因此遵循“如果您不知道它做什么,就不要做”的规则。
简而言之,我重命名旧类型,并使用原始类型名称创建一个新类型。然后,我告诉SQL Server使用自定义类型刷新有关每个存储过程的详细信息。您必须执行此操作,因为即使使用重命名,所有内容仍会参照旧类型进行“编译”。在这种情况下,我需要更改的类型是“ PrizeType”。我希望这有帮助。我也在寻找反馈,所以我学会了:)请注意,您可能需要转到“可编程性”>“类型”>“ [适当的用户类型]”并删除对象。我发现即使使用该语句后,DROP TYPE似乎也不会总是删除该类型。
/* Rename the UDDT you want to replace to another name */
exec sp_rename 'PrizeType', 'PrizeTypeOld', 'USERDATATYPE';
/* Add the updated UDDT with the new definition */
CREATE TYPE [dbo].[PrizeType] AS TABLE(
[Type] [nvarchar](50) NOT NULL,
[Description] [nvarchar](max) NOT NULL,
[ImageUrl] [varchar](max) NULL
);
/* We need to force stored procedures to refresh with the new type... let's take care of that. */
/* Get a cursor over a list of all the stored procedures that may use this and refresh them */
declare sprocs cursor
local static read_only forward_only
for
select specific_name from information_schema.routines where routine_type = 'PROCEDURE'
declare @sprocName varchar(max)
open sprocs
fetch next from sprocs into @sprocName
while @@fetch_status = 0
begin
print 'Updating ' + @sprocName;
exec sp_refreshsqlmodule @sprocName
fetch next from sprocs into @sprocName
end
close sprocs
deallocate sprocs
/* Drop the old type, now that everything's been re-assigned; must do this last */
drop type PrizeTypeOld;
答案 9 :(得分:-3)
简单DROP TYPE
然后CREATE TYPE
再次进行更正/更改?
有一个简单的测试,看它是否在你放弃它之前被定义...就像一个表,proc或函数 - 如果我不在工作,我会看那是什么?
(我也只是在上面撇去......如果我读错了,我会事先道歉!;)