I have a database (Sql Server 2005
) where there are dozens of tables
, each of which has a number of columns
(on average 10-20) with datatype set to nvarchar(max)
. This is absolutely killing performance (some of these columns are being used for joins
and some of the tables have 100K+ rows). I would like to change all of these columns to be varchar(250)
. What would be the best way to automate this? (I could use Management Studio
, or I could create a utility to perform this through an ASP.net
website that has access to the db, whichever is easier).
Asked
Active
Viewed 1.2k times
8

DatabaseCoder
- 2,004
- 2
- 12
- 22

Yaakov Ellis
- 40,752
- 27
- 129
- 174
3 Answers
12
Here's a working script that uses INFORMATION_SCHEMA.COLUMNS
to find all of the *varchar(max)
columns and converts them to varchar(255)
:
declare @schema nvarchar(255)
declare @table nvarchar(255)
declare @col nvarchar(255)
declare @dtype nvarchar(255)
declare @sql nvarchar(max)
declare maxcols cursor for
select
c.TABLE_SCHEMA,
c.TABLE_NAME,
c.COLUMN_NAME,
c.DATA_TYPE
from
INFORMATION_SCHEMA.COLUMNS c
inner join INFORMATION_SCHEMA.TABLES t on
c.TABLE_CATALOG = t.TABLE_CATALOG
and c.TABLE_SCHEMA = t.TABLE_SCHEMA
and c.TABLE_NAME = t.TABLE_NAME
and t.TABLE_TYPE = 'BASE TABLE'
where
c.DATA_TYPE like '%varchar'
and c.CHARACTER_MAXIMUM_LENGTH = -1
open maxcols
fetch next from maxcols into @schema, @table, @col, @dtype
while @@FETCH_STATUS = 0
begin
set @sql = 'alter table [' + @schema + '].[' + @table +
'] alter column [' + @col + '] ' + @dtype + '(255)'
exec sp_executesql @sql
fetch next from maxcols into @schema, @table, @col, @dtype
end
close maxcols
deallocate maxcols
This is about the only use of cursors that I ever condone, but it's a good one. Essentially, it finds all of the *varchar(max)
, builds the alter
statement, and then executes it using sp_executesql
.
Enjoy!

Eric
- 92,005
- 12
- 114
- 115
-
This doesn't work perfectly since it also brings in columns from views – Yaakov Ellis Aug 25 '09 at 11:26
-
Now, how to drop constraints and put them back while doing this, since we cannot alter cols with a constraint in place? – JosephK Sep 08 '16 at 14:59
-
How about including a check to only apply to columns with max length < 255 so that no data is potentially truncated? – windowsgm Jun 07 '17 at 10:03
3
You can easily find them, using:
select 'alter table ' + quotename(o.name) + ' alter column ' + quotename(c.name) + ' varchar(250); '
from sys.columns c
join
sys.objects o
on o.object_id = c.object_id
where o.type = 'U'
and c.user_type_id = 231
and c.max_length = -1
So now just grab the results of your query and run it.
Rob

Rob Farley
- 15,625
- 5
- 44
- 58
-
1Might also be worth mentioning... if you put declare @qry nvarchar(max), and select @qry = (.... for xml path('')); exec sp_executesql @qry; --You can do it all in one step. The .... is the current query I have. But then you can't 'sanity check' it so well. – Rob Farley Aug 25 '09 at 11:26
-
Do you need to take the column nullability into account? Will this alter columns to be nullable because it doesn't specify either way? – Phil Hale Mar 20 '12 at 17:04
0
I think the best way to do this task is to generate script for the current database and then replace nvarchar(max) with varchar(250) on the text file, and then create the new database. after that use the Import/export utilities to transfer the data to the new database.

Wael Dalloul
- 22,172
- 11
- 48
- 57
-
This doesn't work - SSIS will return an error message stating that the column metadata doesn't match between the source and destination tables – Yaakov Ellis Aug 25 '09 at 13:17