As of my knowledge it is impossible to alter/modify a table type.You
can create the type with a different name and then drop the old type
and modify it to the new name
This is kind of a hack, but does seem to work. Below are the steps and an example of modifying a table type. One note is the sp_refreshsqlmodule will fail if the change you made to the table type is a breaking change to that object, typically a procedure.
Use sp_rename to rename the table type, I typically just add z to
the beginning of the name.
Create a new table type with the original name and any modification
you need to make to the table type.
Step through each dependency and run sp_refreshsqlmodule on it.
Drop the renamed table type.
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
WARNING:
This can be destructive to your database, so you'll want to test this on a development environment first.
You should drop the old table type and create a new one. However if it has any dependencies (any stored procedures using it) you won't be able to drop it. I've posted another answer on how to automate the process of temporary dropping all stored procedures, modifying the table table and then restoring the stored procedures.
Here are simple steps that minimize tedium and don't require error-prone semi-automated scripts or pricey tools.
Keep in mind that you can generate DROP/CREATE statements for multiple objects from the Object Explorer Details window (when generated this way, DROP and CREATE scripts are grouped, which makes it easy to insert logic between Drop and Create actions):
Back up you database in case anything goes wrong!
Automatically generate the DROP/CREATE statements for all dependencies (or generate for all "Programmability" objects to eliminate the tedium of finding dependencies).
Between the DROP and CREATE [dependencies] statements (after all DROP, before all CREATE), insert generated DROP/CREATE [table type] statements, making the changes you need with CREATE TYPE.
Run the script, which drops all dependencies/UDTTs and then recreates [UDTTs with alterations]/dependencies.
If you have smaller projects where it might make sense to change the infrastructure architecture, consider eliminating user-defined table types. Entity Framework and similar tools allow you to move most, if not all, of your data logic to your code base where it's easier to maintain.
To generate the DROP/CREATE statements for multiple objects, you can right-click your Database > Tasks > Generate Scripts... (as shown in the screenshot below). Notice:
DROP statements are beforeCREATE statements
DROP statements are in dependency order (i.e. reverse of CREATE)
If you can use a Database project in Visual Studio, you can make your changes in the project and use schema compare to synchronize the changes to your database.
This way, dropping and recreating the dependent objects is handled by the change script.
But, I used Visual Studio community 2015 and I didn't even have to use schema compare.
Using SQL Server Object Explorer, I found my user-defined table type in the DB. I right-mouse clicked on the table-type and selected . This opened a code tab in the IDE with the TSQL code visible and editable. I simply changed the definition (in my case just increased the size of an nvarchar field) and clicked the Update Database button in the top-left of the tab.
Hey Presto! - a quick check in SSMS and the udtt definition has been modified.
I created two stored procedures for this. The first one
create_or_alter_udt_preprocess takes the udt name as input, drops all the stored procs/functions that use the udt, drops the udt, and return a sql script to recreate all the procedures/functions.
The second one
create_or_alter_udt_postprocess takes the script outputted from the first proc and executes it.
With the two procs, changing an udt can be done by:
call create_or_alter_udt_preprocess;
create the udt with a new definition;
call create_or_alter_udt_postprocess;
Use a transaction to avoid losing the original procs in case of errors.
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
Example usage:
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;
Code to set up the example usage:
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;