from - transact sql tutorial
Modificar el tipo definido por el usuario en el servidor SQL (9)
Creé pocos tipos definidos por el usuario en DB como abajo
CREATE TYPE [dbo].[StringID] FROM [nvarchar](20) NOT NULL
y asignados a varias mesas. Mis tablas en db están en varios esquemas (no solo dbo)
Pero me di cuenta de que necesito un campo más grande, y necesito modificar, por ejemplo, aumentar de nvarchar a nvarchar, pero no hay una declaración ALTER TYPE
Necesito una secuencia de comandos que sirva de tabla temporal / cursor y guarde allí todas las tablas y campos donde se utiliza mi tipo. Luego cambie los campos existentes al tipo base, por ejemplo, de CustID [StringID] a CustID [nvarchar (20)]. Elimine el tipo de usuario y vuélvalo a crear con un nuevo tipo, por ejemplo, nvarchar (50) y, finalmente, vuelva a configurar los campos al tipo de usuario
No tengo reglas definidas en los tipos, así que no tengo que descartar reglas y volver a agregarlas
No estoy muy familiarizado con T-Sql, por lo que se agradece cualquier ayuda.
1.Nombrar el antiguo UDT,
2. Ejecutar consulta, 3.Desechar el antiguo UDT.
Como dice Devio, no hay forma de editar un UDT simplemente si está en uso.
Una ronda de trabajo a través de SMS que funcionó para mí fue generar un script de creación y hacer los cambios apropiados; renombrar el UDT existente; ejecutar el script de creación; recompile los sprocs relacionados y descarte la versión renombrada.
Estamos utilizando el siguiente procedimiento, nos permite recrear un tipo desde cero, que es "un comienzo". Renombra el tipo existente, crea el tipo, recompila los procesos almacenados y luego elimina el tipo anterior. Esto se ocupa de los escenarios en los que simplemente al eliminar la antigua definición de tipo se produce un error debido a las referencias a ese tipo.
Ejemplo de uso:
exec RECREATE_TYPE @schema=''dbo'', @typ_nme=''typ_foo'', @sql=''AS TABLE([bar] varchar(10) NOT NULL)''
Código:
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
Esto es lo que normalmente uso, aunque sea un poco manual:
/* 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''
La forma más sencilla de hacerlo es a través del explorador de objetos de Visual Studio, que también se admite en la edición comunitaria.
Una vez que haya establecido una conexión con el servidor SQL, busque el tipo, haga clic con el botón derecho y seleccione Ver código, realice los cambios en el esquema del tipo definido por el usuario y haga clic en actualizar. Visual Studio debería mostrarle todas las dependencias para ese objeto y generar scripts para actualizar el tipo y recompilar las dependencias.
Las soluciones proporcionadas aquí solo se pueden aplicar si los tipos definidos por el usuario se usan solo en las definiciones de tabla, y si las columnas UDT no están indexadas.
Algunos desarrolladores también tienen SP y funciones que utilizan parámetros UDT, que tampoco están cubiertos. (ver comentarios en http://www.sql-server-performance.com/faq/How_to_alter_a%20_UDDT_p1.aspx y en la connect.microsoft.com/SQLServer/feedback/details/319134/… )
La entrada Connect del 2007 finalmente se cerró después de 3 años:
Gracias por enviar esta sugerencia, pero dada su prioridad en relación con los muchos otros elementos en nuestra cola, es poco probable que la completemos. Como tal, estamos cerrando esta sugerencia como "no arreglaremos".
Intenté resolver un problema similar ALTERANDO COLECCIONES DE ESQUEMA XML , y los pasos parecen aplicarse principalmente a ALTER TYPE, también:
Para soltar un UDT, son necesarios los siguientes pasos:
- Si una columna de tabla hace referencia al UDT, debe convertirse al tipo subyacente
- Si la columna de la tabla tiene una restricción predeterminada, elimine la restricción predeterminada
- Si un procedimiento o función tiene parámetros UDT, el procedimiento o la función debe eliminarse
- Si hay un índice en una columna UDT, el índice debe ser eliminado
- Si el índice es una clave principal, todas las claves externas deben ser eliminadas
- Si hay columnas computadas basadas en una columna UDT, las columnas computadas deben ser eliminadas
- Si hay índices en estas columnas calculadas, los índices deben ser eliminados
- Si hay vistas, funciones o procedimientos vinculados a esquemas basados en tablas que contienen columnas UDT, estos objetos se deben eliminar.
Nueva respuesta a una vieja pregunta:
Los proyectos de base de datos de Visual Studio manejan el proceso de soltar y volver a crear cuando se implementan cambios. Eliminará los procesos almacenados que usan UDDT y luego los recreará después de eliminar y recrear el tipo de datos.
Primero, ¿primero DROP TYPE
luego CREATE TYPE
nuevamente con correcciones / alteraciones?
Hay una prueba simple para ver si está definida antes de que la sueltes ... como una tabla, un proceso o una función. Si no estuviera trabajando, ¿qué aspecto tendría?
(Solo lo he visto por encima también ... si lo leí mal, ¡me disculpo por adelantado!)
Hay un buen ejemplo de un script más completo aquí.
Vale la pena señalar que esta secuencia de comandos incluirá vistas si tiene alguna. Lo ejecuté y, en lugar de ejecutarlo en línea, generé un script como salida que luego modifiqué y ejecuté.
Además, si tiene funciones / funciones utilizando los tipos definidos por el usuario, deberá eliminarlos antes de ejecutar su script.
Lección aprendida: en el futuro, no se moleste con los UDT, son más problemáticos de lo que valen.
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/ ha reemplazado http://www.sql-server-performance.com/faq/How_to_alter_a%20_UDDT_p1.aspx