Click here to Skip to main content
15,886,873 members
Articles / Database Development / SQL Server
Article

SQL Server 2000 Collation Changer

Rate me:
Please Sign up or sign in to vote.
4.88/5 (99 votes)
3 Mar 2008CPOL4 min read 636.6K   10.1K   101   196
Change collation order for all text columns in a database

Introduction

Do you have an SQL application that you need to deploy in another country? Do you need to change the collation of your SQL database and all objects in it? If the answer is yes, then this could be a very slow process to do manually. If you run the alter database script as below:

SQL
ALTER DATABASE [My_Database] COLLATE My_Collation

You will find that the database default collation is changed for new columns, but all existing columns will retain the original collation order. Changing the collation on each column is a non-trivial task, as you need to drop all indexes, full text indexes and constraints associated with the column, along with any user-defined functions. Once the collation order has been changed, you can recreate the indexes, constraints and functions. This C# tool simplifies the process by creating an SQL script that does everything for you.

Using the Code

Simply run the program, select your SQL Server database and a new collation order. You have two options: you can either simply get the program to create an SQL script that you can run later (press the "Script Only" button) or you can actually make the changes (press the "Script and Execute" button). Things to note:

  • Always back up your database before running this tool. I cannot guarantee that you will not lose data. A number of the statements cannot be run in a transaction, so there is no way of detecting a failure and rolling back.
  • On SQL Server 2000, nText columns will be recreated so your column order will be slightly different.
  • To run the script, the program sets the database into single user mode to run the ALTER DATABASE [db_name] COLLATE [Collation Name] statement. You should therefore ensure that there are no open connections on the database before running the script (use the stored procedure SP_WHO to identify any open connections).
  • Since the script will drop and then rebuild all indexes and foreign keys in the database, you will find that it could take a long time to complete (possibly hours).
  • All columns will be changed to the new collation order, even if they have a non-default collation before running the script.
  • SQL 2005 support is gradually being added. If you encounter issues or missing functionality, please let me know.
  • If you change from a case-insensitive to a case-sensitive collation order, you may find errors occurring when recreating check constraints and functions. This is because your scripts will be parsed in a case-sensitive manner once the collation order has been changed. To work around this, I would recommend running the script in the program and reviewing the output once the script has run to completion. The error messages relating to each failure will be displayed in red under the code that failed.

Change History

18 January 2006

  • Original posting.

7 March 2006

  • Fixed bug where scripting failed on databases with case-sensitive collation orders. Script no longer drops foreign key constraints unless necessary.

30 August 2006

  • Fixed bug when scripting objects owned by different owners than the owner executing the script are used. May be seen as an error when scripting to #spindtab_____.
  • Fixed bug where scripting did not recreate permissions on table functions after they were recreated.

20 March 2007

  • Triggers now disabled while changes are made.
  • Altered sequence of execution to prevent errors following user feedback.
  • Added some SQL 2005 support. Let me know if you encounter any issues.
  • Resolved issue when recreating a table function where the body of a table function is greater than 4000 characters.
  • Reinstated the functionality to only delete the required indexes and primary keys.

10 October 2007

  • Added support for changing collation where full text indexes exist, including changing language used in the full text search.
  • Fixed issue when insteadof triggers exist on views.
  • Fixed issue where nText columns end up allowing nulls when they were originally declared NOT NULL.
  • SQL 2005 allows collation order of nText columns to be modified. The script has been modified to reflect this new functionality.
  • Fixed issues encountered when user-defined data types are used.
  • Added additional SQL 2005 support, including refactoring scripting logic to allow various parts of the script to be customised for different versions of SQL server. If you need to debug or customise the scripts, it should be a little easier to understand.
  • Converted from VB.NET to C#, as I use C# at work all the time and it is more familiar to me.
  • Moved execution task to a worker thread to give a more responsive UI.
  • Fixed issues when system databases have case-sensitive sort order.

1 March 2008

  • Created new code for handling indexes, statistics and relationships in SQL 2005. This new code uses the 2005 schema views and adds scripting support for new SQL 2005 functionality, such as included columns in non-clustered indexes.
  • Fixed issues where ANSI_NULLS setting is not correct after recreation of table functions.
  • Various minor UI bugs fixed.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer RXP Services
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
NewsRe: Collation Tool Pin
chatchapan27-Mar-07 23:28
chatchapan27-Mar-07 23:28 
GeneralRe: Collation Tool Pin
Roman Ivanashko17-Jul-07 22:42
Roman Ivanashko17-Jul-07 22:42 
GeneralCollation Tool for SQL Server 2005 Pin
Dustin'''RuNNin*bLind27-Mar-07 6:58
Dustin'''RuNNin*bLind27-Mar-07 6:58 
GeneralGenius Pin
Marc Heiligers23-Mar-07 4:46
Marc Heiligers23-Mar-07 4:46 
NewsRe: Genius Pin
Alex Baker23-Mar-07 4:52
Alex Baker23-Mar-07 4:52 
GeneralNo Subject Pin
bailey20321-Mar-07 2:00
bailey20321-Mar-07 2:00 
GeneralRe: Pin
Alex Baker21-Mar-07 2:04
Alex Baker21-Mar-07 2:04 
GeneralRe: Pin
bailey20321-Mar-07 2:46
bailey20321-Mar-07 2:46 
Hi there, thank you for the quick response. here's the background, It is a server migration from SQL 7 to SQL 2000. The database works fine apart from a report function hence the need to change the collation. People are using the database at the moment so I have created a test db from a backup and have attempted to create the script from that.

Thanks

USE [Prism Test]

declare @textptr binary(16)
declare @SQLSegment nvarchar(4000)
declare @C Cursor
set nocount on

create table #SQL (ID int primary key identity(1,1),SQL nText)
insert into #SQL (SQL) values ('alter database [Prism Test] set single_user')
insert into #SQL (SQL) values ('USE [Prism Test]')

insert into #SQL (SQL)
select 'Alter table ['+ u.name + '].['+o.name+'] DROP CONSTRAINT [' + object_name(constid) + ']'
from sysconstraints c
join sysobjects o
on c.id = o.id
join sysusers u
on u.uid = o.uid
where objectproperty(constid,'IsForeignKey')=1
and constid in (

select fk.constid
from sysforeignkeys fk
join syscolumns fc
on fc.colid = fk.fkey
and fc.id = fk.fkeyid
join syscolumns rc
on rc.colid = fk.rkey
and rc.id = fk.rkeyid
where fc.collationid is not null
or rc.collationid is not null
or 1=1 ) --parameter allows all constraints to be dropped

/*script out dropping of check constraints */



insert into #SQL (SQL)
select 'Alter table ['+ u.name + '].['+o.name+'] drop constraint ['+object_name(cs.constid)+']'
from sysconstraints cs
join sysobjects o
on cs.id = o.id
join sysusers u
on u.uid = o.uid
where objectproperty(cs.constid,'IsCheckCnst') = 1


/*drop calculated columns*/



insert into #SQL (SQL)
select 'ALTER TABLE ['+ u.name + '].['+o.name+'] drop column ['+c.name+']'
from syscolumns c
join sysobjects o
on c.id = o.id
join sysusers u
on u.uid = o.uid
where c.iscomputed=1
and objectproperty(c.id,'IsMSShipped')=0
and objectproperty(c.id,'IsTable')=1


--drop Table Functions

insert into #SQL (SQL)
select 'DROP FUNCTION ['+ u.name + '].['+o.name+']'
from sysobjects o
join sysusers u
on o.uid = u.uid
where objectproperty(id,'IsMSShipped')=0
and objectproperty(id,'IsTableFunction')=1

-- script drop of indexes - we will also populate a temp table that helps recreate the indexes later
create table #spindtab
(
-- owner sysname collate database_default NOT NULL,
objectname sysname collate database_default NOT NULL,
index_name sysname collate database_default NOT NULL,
stats int,
groupname sysname collate database_default NOT NULL,
index_keys nvarchar(3000) collate database_default NOT NULL, -- see @IX_keys above for length descr
OrigFillFactor tinyint,
IsAutoStatistic bit
)


--generate SQL to do indexes

declare @IX_indid smallint, -- the index id of an index
@IX_groupid smallint, -- the filegroup id of an index
@IX_indname sysname,
@IX_groupname sysname,
@IX_status int,
@IX_keys nvarchar(3000),
@IX_dbname sysname,
@IX_ObjID int,
@IX_ObjName sysname,
@IX_OrigFillFactor tinyint,
@IX_IsAutoStatistic bit

-- Check to see the the table exists and initialize @IX_objid.

-- OPEN CURSOR OVER INDEXES (skip stats: bug shiloh_51196)
declare ms_crs_ind cursor local static for
select i.id, '['+u.name+'].['+o.name+']' as objectname, i.indid, i.groupid, i.name, i.status, i.OrigFillFactor, case when (i.status & 64) = 0 then 0 else isnull(INDEXPROPERTY(i.id,i.name,'IsAutoStatistics'),0) end as IsAutoStatistic from sysindexes i
join sysobjects o
on i.id = o.id
join sysusers u
on u.uid = o.uid
where /*id = @IX_objid and */i.indid > 0 and i.indid < 255
and objectproperty(i.id,'ISMSSHIPPED')=0 and objectproperty(i.id,'IsTableFunction')=0
order by object_name(i.id),i.indid


open ms_crs_ind
fetch ms_crs_ind into @IX_objid, @IX_ObjName,@IX_indid, @IX_groupid, @IX_indname, @IX_status, @IX_OrigFillFactor, @IX_IsAutoStatistic


-- Now check out each index, figure out its type and keys and
-- save the info in a temporary table that we'll print out at the end.
while @@fetch_status >= 0
begin
-- First we'll figure out what the keys are.
declare @IX_i int, @IX_thiskey nvarchar(133) -- 128+5
declare @rebuild_index bit

select @IX_keys = '[' + index_col(@IX_objname, @IX_indid, 1)+']', @IX_i = 2, @rebuild_index=1 --parameter from application can force all to be rebuilt
if (indexkey_property(@IX_objid, @IX_indid, 1, 'IsDescending') = 1)
set @IX_keys = @IX_keys + ' DESC'

if (select collationid from syscolumns where id=@IX_objid and colid=indexkey_property(@IX_objid, @IX_indid, 1, 'columnid')) is not null
set @rebuild_index=1


set @IX_thiskey = '[' + index_col(@IX_objname, @IX_indid, @IX_i) + ']'
if ((@IX_thiskey is not null) and (indexkey_property(@IX_objid, @IX_indid, @IX_i, 'IsDescending') = 1))
set @IX_thiskey = @IX_thiskey + ' DESC'

if (select collationid from syscolumns where id=@IX_objid and colid=indexkey_property(@IX_objid, @IX_indid, @IX_i, 'columnid')) is not null
set @rebuild_index=1

while (@IX_thiskey is not null )
begin
select @IX_keys = @IX_keys + ', ' + @IX_thiskey, @IX_i = @IX_i + 1


if (select collationid from syscolumns where id=@IX_objid and colid=indexkey_property(@IX_objid, @IX_indid, @IX_i, 'columnid')) is not null
set @rebuild_index=1

set @IX_thiskey = '[' + index_col(@IX_objname, @IX_indid, @IX_i) + ']'
if ((@IX_thiskey is not null) and (indexkey_property(@IX_objid, @IX_indid, @IX_i, 'IsDescending') = 1))
select @IX_thiskey = @IX_thiskey + ' DESC'
end

select @IX_groupname = groupname from sysfilegroups where groupid = @IX_groupid

-- INSERT ROW FOR INDEX
if @rebuild_index =1
insert into #spindtab values ( @IX_ObjName,@IX_indname, @IX_status, @IX_groupname, @IX_keys, @IX_OrigFillFactor, @IX_IsAutoStatistic)

-- Next index
fetch ms_crs_ind into @IX_objid, @IX_ObjName, @IX_indid, @IX_groupid, @IX_indname, @IX_status, @IX_OrigFillFactor, @IX_IsAutoStatistic
end
deallocate ms_crs_ind

-- SET UP SOME CONSTANT VALUES FOR OUTPUT QUERY

declare @IX_empty varchar(1) select @IX_empty = ''
declare @IX_des1 varchar(35), -- 35 matches spt_values
@IX_des2 varchar(35),
@IX_des4 varchar(35),
@IX_des32 varchar(35),
@IX_des64 varchar(35),
@IX_des2048 varchar(35),
@IX_des4096 varchar(35),
@IX_des8388608 varchar(35),
@IX_des16777216 varchar(35)

select @IX_des1 = name from master.dbo.spt_values where type = 'I' and number = 1 --ignoor duplicate keys

select @IX_des2 = name from master.dbo.spt_values where type = 'I' and number = 2 --unique
select @IX_des4 = name from master.dbo.spt_values where type = 'I' and number = 4 --ignoor duplicate rows
select @IX_des32 = name from master.dbo.spt_values where type = 'I' and number = 32 --hypothetical
select @IX_des64 = name from master.dbo.spt_values where type = 'I' and number = 64 --statistics
select @IX_des2048 = name from master.dbo.spt_values where type = 'I' and number = 2048 --primary key
select @IX_des4096 = name from master.dbo.spt_values where type = 'I' and number = 4096 --unique key
select @IX_des8388608 = name from master.dbo.spt_values where type = 'I' and number = 8388608 --auto create
select @IX_des16777216 = name from master.dbo.spt_values where type = 'I' and number = 16777216 --stats no recompute




insert into #SQL
select case when (stats & 4096)<>0 or (stats & 2048) <> 0 then
--Constraint
'ALTER TABLE '+objectname+' DROP CONSTRAINT ['+index_name+'] '

when (stats & 64) <> 0 then

'DROP STATISTICS '+objectname+'.['+index_name+'] '

else
-- index

'DROP INDEX '+objectname+'.['+ index_name +'] '
end
from #spindtab






-- script the changing of the database collation
insert into #SQL (SQL) values ('USE [MASTER]')
insert into #SQL (SQL) values ('alter database [Prism Test] collate Latin1_General_CI_AS')
insert into #SQL (SQL) values ('USE [Prism Test]')

-- Script out the creation of the table functions now as they may be used in triggers that will execute when columns are updated!

--first switch to use the correct database
insert into #SQL (SQL) values ('')

--get a text pointer
SELECT @textptr = TEXTPTR(SQL) FROM #SQL where ID = (select max(ID) from #SQL)

set @SQLSegment = '
USE [Prism Test]
'

UPDATETEXT #SQL.SQL @textptr NULL 0 @SQLSegment


--recreate functions - make sure owner name is specified!

declare @fn_name sysname,
@fn_id int,
@fn_idlast int,
@fn_last sysname,
@fn_owner sysname,
@fn_testText nvarchar(4000),
@fn_posCreateFn int,
@fn_posCommentStart int,
@fn_posCommentEnd int,
@fn_offset int,
@fn_posFunctionName int,
@fn_posObjectName int

set @fn_idlast =0

set @C = cursor for
select o.name as functionName,
o.id,
sc.text,
u.name
from sysobjects o
join syscomments sc
on o.id = sc.id
join sysusers u
on u.uid = o.uid
where objectproperty(o.id,'IsTableFunction') =1
order by o.id,
sc.colid

open @C
fetch next from @C into @fn_name, @fn_id, @SQLSegment, @fn_owner
while @@Fetch_Status=0
begin
if @fn_id<>@fn_idLast
begin

--add a row for our data
insert into #SQL (SQL) values ('')

--get a text pointer
SELECT @textptr = TEXTPTR(SQL) FROM #SQL where ID = (select max(ID) from #SQL)

set @fn_idLast =@fn_id

-- now look at the create function part of the SQL, make sure that the owner
-- name is specified

set @fn_posCreateFn = patindex('%create%function%', @SQLSegment)
set @fn_posCommentStart = patindex('%/*%', @SQLSegment)
set @fn_offset = 1
set @fn_testText = @SQLSegment
-- it is possible that there are create function statments in comments at the
-- start of the SQL so look for the one that actually creates the function

while @fn_posCommentStart <@fn_posCreateFn and @fn_posCommentStart<>0
begin
set @fn_posCommentEnd = patindex('%*/%', @fn_testText)
set @fn_offset = @fn_offset+@fn_posCommentEnd+1
set @fn_testText = substring(@SQLSegment, @fn_offset, len(@SQLSegment) - @fn_offset)
set @fn_posCreateFn = patindex('%create%function%', @fn_testText collate latin1_general_ci_ai)
set @fn_posCommentStart = patindex('%/*%', @fn_testText)
end

-- now look to see if the owner name is specified, there should be a
-- . before the function name so inspect the text between the word function and the actual
-- function name

set @fn_posFunctionName = charindex('function' collate latin1_general_ci_ai, @SQLSegment collate latin1_general_ci_ai, @fn_posCreateFn-1+@fn_offset)
if @fn_posFunctionName>0
set @fn_posFunctionName=@fn_posFunctionName+8 --number of characters in the word function

set @fn_posObjectName = charindex(@fn_name collate latin1_general_ci_ai, @SQLSegment collate latin1_general_ci_ai, @fn_posFunctionName)

set @fn_testText= substring(@SQLSegment,@fn_posFunctionName,@fn_posObjectName-@fn_posFunctionName)

if charindex('.',@fn_testText,1)=0
begin
-- the owner name is missing, add it
set @SQLSegment = left(@SQLSegment, @fn_posFunctionName) + '['+@fn_owner+'].'+substring(@SQLSegment, @fn_posObjectName,4000)

end

end

UPDATETEXT #SQL.SQL @textptr NULL 0 @SQLSegment

fetch next from @C into @fn_name, @fn_id, @SQLSegment, @fn_owner
end
Close @C
deallocate @C


-- now the permissions on the functions that have been recreated
insert into #SQL (SQL)
select case p.protecttype
when 206 then 'DENY '
else 'GRANT ' end +
case p.action
when 193 then 'SELECT'
when 26 then 'REFERENCES'
end+
' on ['+user_name(o.uid)+'].['+o.name+'] to ['+user_name(p.uid)+']' +
case when p.protecttype = 204 then ' WITH GRANT OPTION' else '' end
from sysprotects p
join sysobjects o
on p.id = o.id
where objectproperty(o.id,'IsTableFunction') =1

-- script out the changing of column level collation

declare @CC_TableName sysname,
@CC_UserName sysname,
@ColName sysname,
@CC_Length nvarchar(100),
@CC_TypeName sysname,
@CC_OtherText nvarchar(4000),
@CC_NullText nvarchar(100),
@CC_id int

set @C = cursor for

select o.id,
u.name,
o.name as tablename,
c.name as colname,
case when t.name like 'n%' then cast(c.length / 2 as nvarchar(100)) else cast(c.length as nvarchar(100)) end as Length,
t.name as typename,
case when c.isnullable=1 then 'NULL' else 'NOT NULL' end as nullable
from sysobjects o
join syscolumns c
on o.id = c.id
join systypes t
on t.xtype = c.xtype
and t.xusertype = c.xusertype
join sysusers u
on u.uid = o.uid
where o.type ='U'
and objectproperty(o.id,'IsMSShipped')=0
and c.collationid is not null
--and c.collation <> cast(DATABASEPROPERTYEX(DB_NAME(),'collation') as sysname)

open @C


fetch next from @C into @CC_id,@CC_UserName,@CC_TableName, @ColName, @CC_Length, @CC_TypeName,@CC_NullText
while @@Fetch_Status = 0
begin
if @CC_TypeName COLLATE DATABASE_DEFAULT in ('ntext','text')
begin
-- we can not use the alter table statment to change column level collation on text columns
--we need to do each of these as a separate transaction dur to the risks of errors

set @SQLSegment = '
declare @InError bit
set @InError =0
begin transaction
-- add a temp column
exec (''Alter table ['+@CC_UserName+'].['+@CC_TableName+'] add [____temp] [' + @CC_TypeName + ']'')

-- copy data to temp column
if @@error<>0 set @InError =1
if @@error = 0
exec (''update ['+@CC_UserName+'].['+@CC_TableName+'] set [____temp] =[' + @ColName + ']'')


-- readd origional column
if @@error<>0 set @InError =1
if @@error = 0'
-- if default constraint must add it

if exists ( select *
from sysconstraints
where id = @CC_id
and col_name(@CC_id,colid) = @ColName
and (status & 5) = 5 )

-- if there are default constraints add a bit to do that
set @SQLSegment = @SQLSegment +

(select '

exec (''Alter table ['+@CC_UserName+'].['+@CC_TableName+'] drop constraint [' + object_name(c.constid) + ']'')
if @@error<>0 set @InError =1
if @@error = 0

exec (''Alter table ['+@CC_UserName+'].['+@CC_TableName+'] drop column [' + @ColName + ']'')
if @@error<>0 set @InError =1
if @@error = 0

exec ('' ALTER TABLE ['+@CC_UserName+'].['+@CC_TableName+'] ADD ['+o.name+'] [' + @CC_TypeName + '] CONSTRAINT [' + object_name(c.constid) + '] DEFAULT ' + replace(t.text,'''','''''') + ' '')'
from sysconstraints c
join syscolumns o
on c.id = o.id
and c.colid = o.colid
join syscomments t
on t.id = c.constid
where c.id = @CC_id
and (c.status & 5) = 5
and col_name(c.id,c.colid) = @ColName) --default constraint

else

set @SQLSegment = @SQLSegment + '
exec (''Alter table ['+@CC_UserName+'].['+@CC_TableName+'] drop column [' + @ColName + ']'')

-- drop origional column
if @@error<>0 set @InError =1
if @@error = 0

exec (''Alter table ['+@CC_UserName+'].['+@CC_TableName+'] add [' + @ColName+'] [' + @CC_TypeName + '] '')'

set @SQLSegment = @SQLSegment + '
-- Copy data back to origional column
if @@error<>0 set @InError =1
if @@error = 0
exec (''update ['+@CC_UserName+'].['+@CC_TableName+'] set [' + @ColName + '] = [____temp] '')

-- drop temp column
if @@error<>0 set @InError =1
if @@error = 0
exec (''alter table ['+@CC_UserName+'].['+@CC_TableName+'] drop column [____temp]'')
'
if @CC_TypeName = 'NOT NULL'

set @SQLSegment = @SQLSegment + '
-- now set the appropriate nullability
if @@error<>0 set @InError =1
if @@error = 0
exec (''Alter table ['+@CC_UserName+'].['+@CC_TableName+'] Alter column [' + @ColName+'] [' + @CC_TypeName + '] '+@CC_NullText+' '')'

set @SQLSegment = @SQLSegment + '
if @@error<>0 set @InError =1
if @@error = 0
commit transaction
else
rollback transaction

'

insert into #SQL values (@SQLSegment)


end
else
begin
-- normal columns
set @SQLSegment = 'Alter table ['+@CC_UserName+'].['+@CC_TableName COLLATE DATABASE_DEFAULT+'] Alter Column ['+@ColName COLLATE DATABASE_DEFAULT+ '] ['+@CC_TypeName COLLATE DATABASE_DEFAULT+']'

if @CC_TypeName COLLATE DATABASE_DEFAULT in ('nVarchar', 'varchar','char','nchar')
set @SQLSegment = @SQLSegment COLLATE DATABASE_DEFAULT +' ('+@CC_Length COLLATE DATABASE_DEFAULT + ')'

set @SQLSegment = @SQLSegment COLLATE DATABASE_DEFAULT + ' COLLATE DATABASE_DEFAULT ' + @CC_NullText COLLATE DATABASE_DEFAULT + '
'
insert into #SQL values (@SQLSegment)

end
fetch next from @C into @CC_id,@CC_UserName,@CC_TableName, @ColName, @CC_Length, @CC_TypeName,@CC_NullText
end

close @C
deallocate @C

-- script out recreation of check constraints


insert into #SQL
select 'Alter table ['+u.name+'].[' + o.name + '] WITH NOCHECK ADD CONSTRAINT ['+object_name(cs.constid)+'] CHECK '+sc.text + '
' + case when objectproperty(cs.constid,'CnstIsDisabled') = 1 then 'Alter table ['+u.name+'].[' + o.name + '] NOCHECK CONSTRAINT ['+object_name(cs.constid)+']' else '' end
from sysconstraints cs
join syscomments sc
on sc.id = cs.constid
join sysobjects o
on o.id = cs.id
join sysusers u
on u.uid = o.uid
where objectproperty(cs.constid,'IsCheckCnst') = 1

--script out recreation of calculated columns

insert into #SQL
select 'ALTER TABLE ['+u.name+'].['+o.name+'] ADD ['+c.name+'] AS '+sc.text
from syscolumns c
join syscomments sc
on c.id = sc.id
and c.colid = sc.number
join sysobjects o
on o.id = c.id
join sysusers u
on o.uid = u.uid
where c.iscomputed=1
and objectproperty(c.id,'IsMSShipped')=0
and objectproperty(c.id,'IsTable')=1

-- script out the recreation of indexes


-- DISPLAY THE RESULTS


insert into #SQL
select case when (stats & 4096)<>0 or (stats & 2048) <> 0 then
--Constraint
'ALTER TABLE '+objectname+' ADD CONSTRAINT ['+index_name+'] '
+ case when (stats & 2048)<>0 then 'PRIMARY KEY ' else 'UNIQUE ' end
+ case when (stats & 16)<>0 then 'clustered' else 'nonclustered' end
+ ' ('+index_keys+')'
+ case when OrigFillFactor >0 then ' WITH FILLFACTOR =' + cast(OrigFillFactor as nvarchar(3)) else @IX_empty end
+ ' ON ['+groupname+']
' collate database_default

when (stats & 64) <> 0 then

--statistics
'CREATE STATISTICS ['+index_name+'] on '+objectname+' ('+index_keys+')'
+ case when (stats & 16777216)<>0 then ' WITH ' else @IX_empty end
+ case when (stats & 16777216)<>0 then @IX_des16777216 else @IX_empty end
else
-- index

'CREATE ' + case when (stats & 2)<>0 then @IX_des2 +' ' else @IX_empty end +case when (stats & 16)<>0 then 'clustered' else 'nonclustered' end +' INDEX'
+ ' ['+ index_name +'] on '+objectname+' ('+index_keys+')'
+ case when OrigFillFactor >0 or (stats & 1) <> 0 or (stats & 16777216) <> 0 then ' WITH ' else @IX_empty end
+ case when OrigFillFactor >0 then 'PAD_INDEX, FILLFACTOR = ' +cast(OrigFillFactor as nvarchar(3) ) else @IX_empty end
+ case when (stats & 1) <> 0 then ', '+ @IX_des1 else @IX_empty end
+ case when (stats & 16777216) <> 0 then ', '+ @IX_des16777216 else @IX_empty end
+ ' ON ['+groupname+']
'
end
from #spindtab
where IsAutoStatistic=0 --do not recreate auto statistics
drop table #spindtab


-- script recreation of foiegn keys

-- script out foreign keys

declare @FK_KeyName sysname,
@FK_TableName sysname,
@FK_ReferencedTable sysname,
@ConstID int,
@Col1 sysname,
@Col2 sysname,
@ColList1 nvarchar(2000),
@ColList2 nvarchar(2000),
@CnstIsUpdateCascade bit,
@CnstIsNotRepl bit,
@CnstIsDeleteCascade bit,
@CnstIsDisabled bit,
@C2 cursor




set @C = cursor for

select '[' + u.name + '].[' + o.name + ']' as TableName,
object_name(constid) as KeyName,
( select distinct '['+fu.name+'].['+ro.name+']'
from sysforeignkeys fk
join sysobjects ro
on ro.id = fk.rkeyid
join sysusers fu
on fu.uid = ro.uid
where fk.constid = c.constid) as ReferencedTable,
constid,
objectproperty(constid,'CnstIsUpdateCascade') CnstIsUpdateCascade,
objectproperty(constid,'CnstIsDeleteCascade') CnstIsDeleteCascade,
objectproperty(constid,'CnstIsNotRepl') CnstIsNotRepl,
objectproperty(constid,'CnstIsDisabled') CnstIsDisabled
from sysconstraints c
join sysobjects o
on c.id = o.id
join sysusers u
on u.uid = o.uid
where objectproperty(constid,'IsForeignKey')=1
and constid in (

select fk.constid
from sysforeignkeys fk
join syscolumns fc
on fc.colid = fk.fkey
and fc.id = fk.fkeyid
join syscolumns rc
on rc.colid = fk.rkey
and rc.id = fk.rkeyid
where fc.collationid is not null
or rc.collationid is not null
or 1=1) --paramater allows all constraints to be dropped

open @C

fetch next from @C into @FK_TableName, @FK_KeyName, @FK_ReferencedTable,@ConstID, @CnstIsUpdateCascade, @CnstIsDeleteCascade, @CnstIsNotRepl,@CnstIsDisabled
while @@fetch_Status =0
begin
set @ColList1 = ''
set @ColList2 = ''

set @C2 = Cursor for
select fc.name,
rc.name

from sysforeignkeys fk
join syscolumns fc
on fc.colid = fk.fkey
and fc.id = fk.fkeyid
join syscolumns rc
on rc.colid = fk.rkey
and rc.id = fk.rkeyid
where fk.constid = @ConstID

open @C2
fetch next from @C2 into @Col1, @Col2
while @@Fetch_status=0
begin
if len(@ColList1) > 0
set @ColList1 = @ColList1 collate database_default+', '
if len(@ColList2) > 0
set @ColList2 = @ColList2 collate database_default+', '

set @ColList1 = @ColList1 collate database_default +'[' + @Col1 collate database_default + ']'
set @ColList2 = @ColList2 collate database_default +'[' + @Col2 collate database_default + ']'

fetch next from @C2 into @Col1, @Col2
end
close @C2
deallocate @C2

set @SQLSegment = 'Alter table '+ @FK_TableName collate database_default + ' WITH NOCHECK ADD CONSTRAINT [' + @FK_KeyName collate database_default + '] FOREIGN KEY ('+@ColList1 collate database_default + ') REFERENCES ' + @FK_ReferencedTable collate database_default+' ('+ @ColList2 collate database_default +')'
if @CnstIsUpdateCascade =1
set @SQLSegment =@SQLSegment + ' ON UPDATE CASCADE'

if @CnstIsDeleteCascade =1
set @SQLSegment =@SQLSegment + ' ON DELETE CASCADE'

if @CnstIsNotRepl =1
set @SQLSegment =@SQLSegment + ' NOT FOR REPLICATION'
set @SQLSegment = @SQLSegment +'
'

insert into #SQL values (@SQLSegment)

if @CnstIsDisabled=1
begin
set @SQLSegment = 'Alter table '+ @FK_TableName + ' NOCHECK CONSTRAINT [' + @FK_KeyName + ']
'
insert into #SQL values (@SQLSegment)
end

fetch next from @C into @FK_TableName, @FK_KeyName, @FK_ReferencedTable,@ConstID, @CnstIsUpdateCascade, @CnstIsDeleteCascade, @CnstIsNotRepl,@CnstIsDisabled
end

close @C
deallocate @C

-- finally set back to multi user access
insert into #SQL values ('alter database [Prism Test] set multi_user')

select * from #SQL order by ID

return
GeneralRe: Success Pin
bailey20322-Mar-07 7:14
bailey20322-Mar-07 7:14 
GeneralRe: Success Pin
Alex Baker23-Mar-07 4:49
Alex Baker23-Mar-07 4:49 
GeneralDatabase Collation need help Pin
ruylopez805-Mar-07 22:27
ruylopez805-Mar-07 22:27 
GeneralRe: Database Collation need help Pin
Alex Baker19-Mar-07 6:09
Alex Baker19-Mar-07 6:09 
GeneralRe: Database Collation need help Pin
ruylopez8025-Mar-07 20:59
ruylopez8025-Mar-07 20:59 
QuestionData Type : text : to null Pin
Sandy Campbell2-Mar-07 13:19
Sandy Campbell2-Mar-07 13:19 
AnswerRe: Data Type : text : to null Pin
Alex Baker19-Mar-07 6:06
Alex Baker19-Mar-07 6:06 
QuestionI got an error Pin
David (Canada)8-Feb-07 3:06
David (Canada)8-Feb-07 3:06 
AnswerRe: I got an error Pin
Alex Baker19-Mar-07 23:14
Alex Baker19-Mar-07 23:14 
GeneralMuchas Gracias!! (Thank You!!!) Pin
fsosa5-Feb-07 8:38
fsosa5-Feb-07 8:38 
GeneralGreat Job ! Pin
rleboite30-Jan-07 3:20
rleboite30-Jan-07 3:20 
GeneralThanks !!! Pin
AndersWes24-Jan-07 23:26
AndersWes24-Jan-07 23:26 
QuestionErrors... Pin
Mühring Olivier18-Jan-07 22:16
Mühring Olivier18-Jan-07 22:16 
QuestionRe: Errors... Pin
Mühring Olivier19-Jan-07 1:56
Mühring Olivier19-Jan-07 1:56 
AnswerRe: Errors... Pin
Alex Baker5-Feb-07 21:11
Alex Baker5-Feb-07 21:11 
GeneralRe: Errors... Pin
Alex Baker25-Mar-07 21:02
Alex Baker25-Mar-07 21:02 
GeneralGreat tool for changing collations! Pin
ShanPlourde11-Dec-06 18:33
ShanPlourde11-Dec-06 18:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.