In order to change the collation of the Microsoft Dynamics CRM 4 database, you should use this query:
you can run this query in SQL (it is unsupported and you should test it at a dummy organisation, but it worked fine for me)
Just stop the async service and SQL agent service before running this script.
--change collation
use test_MSCRM
declare @target_collation sysname
drop function [dbo].[fn_GetFormatStrings]
exec [p_SetDbCollation] 'test_MSCRM', 'Latin1_General_CI_AI'
go
create function [dbo].[fn_GetFormatStrings]()
returns @FormatStrings table (
 DateFormat nvarchar(255),
 TimeFormat nvarchar(255),
 NumberLanguageCode nvarchar(10),
 CalendarType nvarchar(50),
 NumberFormat_0_Precision nvarchar(255),
 NumberFormat_1_Precision nvarchar(255),
 NumberFormat_2_Precision nvarchar(255),
 NumberFormat_3_Precision nvarchar(255),
 NumberFormat_4_Precision nvarchar(255),
 NumberFormat_5_Precision nvarchar(255),
 CurrencyFormat_0_Precision nvarchar(255),
 CurrencyFormat_1_Precision nvarchar(255),
 CurrencyFormat_2_Precision nvarchar(255),
 CurrencyFormat_3_Precision nvarchar(255),
 CurrencyFormat_4_Precision nvarchar(255),
 CurrencyFormat_5_Precision nvarchar(255)
)
as
begin
 declare @CurrencySymbol nvarchar(10)
 declare @CurrencyFormatCode int
 declare @NumberLocale int
 declare @CalendarType nvarchar(50)
 declare @NumberGroupFormat nvarchar(50)
 declare @NegativeFormatCode int
 declare @NegativeCurrencyFormatCode int
 declare @DateFormatString nvarchar(255)
 declare @TimeFormatString nvarchar(255)
 declare @NumberLanguageCode nvarchar(10)
 
 declare @s1 nvarchar(255)
 declare @s2 nvarchar(255)
 declare @s3 nvarchar(255)
 declare @s4 nvarchar(255)
 declare @s5 nvarchar(255)
 declare @s6 nvarchar(255)
 declare @s7 nvarchar(255)
 declare @s8 nvarchar(255)
 declare @s9 nvarchar(255)
 declare @s10 nvarchar(255)
 declare @s11 nvarchar(255)
 declare @s12 nvarchar(255)
 select top 1
  @CurrencySymbol =
  case o.currencydisplayoption
   when 0 then t.currencysymbol
   when 1 then t.isocurrencycode
   else t.currencysymbol
  end
 from
  FilteredOrganization AS o inner join
  FilteredTransactionCurrency AS t on o.basecurrencyid = t.transactioncurrencyid
 select top 1
  @CurrencyFormatCode = currencyformatcode,
  @NumberLocale = localeid,
  @CalendarType = 
  case calendartype
   when 1 then 'Japanese'
   when 2 then 'Korea'
   when 3 then 'Taiwan'
   when 4 then 'Gregorian US English'
   when 5 then 'Gregorian Arabic'
   when 6 then 'Gregorian Middle East French'
   when 7 then 'Gregorian Transliterated English'
   when 8 then 'Gregorian Transliterated French'
   else 'Gregorian'
  end,
  @NumberGroupFormat = numbergroupformat,
  @NegativeFormatCode = negativeformatcode,
  @NegativeCurrencyFormatCode = negativecurrencyformatcode,
  @DateFormatString = replace(dateformatstring, '/', '\' + dateseparator),
  @TimeFormatString = replace(timeformatstring, ':', '\' + timeseparator)
 from
  FilteredUserSettings
 where
  systemuserid = dbo.fn_FindUserGuid()
 set @NumberLanguageCode =
  case @NumberLocale
   when 1025 then 'ar-SA'
   when 1026 then 'bg-BG'
   when 1027 then 'ca-ES'
   when 1028 then 'zh-TW'
   when 1029 then 'cs-CZ'
   when 1030 then 'da-DK'
   when 1031 then 'de-DE'
   when 1032 then 'el-GR'
   when 1033 then 'en-US'
   when 1035 then 'fi-FI'
   when 1036 then 'fr-FR'
   when 1037 then 'he-IL'
   when 1038 then 'hu-HU'
   when 1039 then 'is-IS'
   when 1040 then 'it-IT'
   when 1041 then 'ja-JP'
   when 1042 then 'ko-KR'
   when 1043 then 'nl-NL'
   when 1044 then 'nb-NO'
   when 1045 then 'pl-PL'
   when 1046 then 'pt-BR'
   when 1047 then 'rm-CH'
   when 1048 then 'ro-RO'
   when 1049 then 'ru-RU'
   when 1050 then 'hr-HR'
   when 1051 then 'sk-SK'
   when 1052 then 'sq-AL'
   when 1053 then 'sv-SE'
   when 1054 then 'th-TH'
   when 1055 then 'tr-TR'
   when 1056 then 'ur-PK'
   when 1057 then 'id-ID'
   when 1058 then 'uk-UA'
   when 1059 then 'be-BY'
   when 1060 then 'sl-SI'
   when 1061 then 'et-EE'
   when 1062 then 'lv-LV'
   when 1063 then 'lt-LT'
   when 1065 then 'fa-IR'
   when 1066 then 'vi-VN'
   when 1067 then 'hy-AM'
   when 1068 then 'az-Latn-AZ'
   when 1069 then 'eu-ES'
   when 1071 then 'mk-MK'
   when 1074 then 'tn-ZA'
   when 1076 then 'xh-ZA'
   when 1077 then 'zu-ZA'
   when 1078 then 'af-ZA'
   when 1079 then 'ka-GE'
   when 1080 then 'fo-FO'
   when 1081 then 'hi-IN'
   when 1082 then 'mt-MT'
   when 1083 then 'se-NO'
   when 1086 then 'ms-MY'
   when 1087 then 'kk-KZ'
   when 1088 then 'ky-KG'
   when 1089 then 'sw-KE'
   when 1091 then 'uz-Latn-UZ'
   when 1092 then 'tt-RU'
   when 1094 then 'pa-IN'
   when 1095 then 'gu-IN'
   when 1097 then 'ta-IN'
   when 1098 then 'te-IN'
   when 1099 then 'kn-IN'
   when 1102 then 'mr-IN'
   when 1103 then 'sa-IN'
   when 1104 then 'mn-MN'
   when 1106 then 'cy-GB'
   when 1110 then 'gl-ES'
   when 1111 then 'kok-IN'
   when 1114 then 'syr-SY'
   when 1122 then 'fy-NL'
   when 1124 then 'fil-PH'
   when 1125 then 'dv-MV'
   when 1131 then 'quz-BO'
   when 1132 then 'ns-ZA'
   when 1134 then 'lb-LU'
   when 1146 then 'arn-CL'
   when 1148 then 'moh-CA'
   when 1153 then 'mi-NZ'
   when 2049 then 'ar-IQ'
   when 2052 then 'zh-CN'
   when 2055 then 'de-CH'
   when 2057 then 'en-GB'
   when 2058 then 'es-MX'
   when 2060 then 'fr-BE'
   when 2064 then 'it-CH'
   when 2067 then 'nl-BE'
   when 2068 then 'nn-NO'
   when 2070 then 'pt-PT'
   when 2074 then 'sr-Latn-CS'
   when 2077 then 'sv-FI'
   when 2092 then 'az-Cyrl-AZ'
   when 2107 then 'se-SE'
   when 2108 then 'ga-IE'
   when 2110 then 'ms-BN'
   when 2115 then 'uz-Cyrl-UZ'
   when 2141 then 'iu-Latn-CA'
   when 2155 then 'quz-EC'
   when 3073 then 'ar-EG'
   when 3076 then 'zh-HK'
   when 3079 then 'de-AT'
   when 3081 then 'en-AU'
   when 3082 then 'es-ES'
   when 3084 then 'fr-CA'
   when 3098 then 'sr-Cyrl-CS'
   when 3131 then 'se-FI'
   when 3179 then 'quz-PE'
   when 4097 then 'ar-LY'
   when 4100 then 'zh-SG'
   when 4103 then 'de-LU'
   when 4105 then 'en-CA'
   when 4106 then 'es-GT'
   when 4108 then 'fr-CH'
   when 4122 then 'hr-BA'
   when 4155 then 'smj-NO'
   when 5121 then 'ar-DZ'
   when 5124 then 'zh-MO'
   when 5127 then 'de-LI'
   when 5129 then 'en-NZ'
   when 5130 then 'es-CR'
   when 5132 then 'fr-LU'
   when 5146 then 'bs-Latn-BA'
   when 5179 then 'smj-SE'
   when 6145 then 'ar-MA'
   when 6153 then 'en-IE'
   when 6154 then 'es-PA'
   when 6156 then 'fr-MC'
   when 6170 then 'sr-Latn-BA'
   when 6203 then 'sma-NO'
   when 7169 then 'ar-TN'
   when 7177 then 'en-ZA'
   when 7178 then 'es-DO'
   when 7194 then 'sr-Cyrl-BA'
   when 7227 then 'sma-SE'
   when 8193 then 'ar-OM'
   when 8201 then 'en-JM'
   when 8202 then 'es-VE'
   when 8218 then 'bs-Cyrl-BA'
   when 8251 then 'sms-FI'
   when 9217 then 'ar-YE'
   when 9225 then 'en-029'
   when 9226 then 'es-CO'
   when 9275 then 'smn-FI'
   when 10241 then 'ar-SY'
   when 10249 then 'en-BZ'
   when 10250 then 'es-PE'
   when 11265 then 'ar-JO'
   when 11273 then 'en-TT'
   when 11274 then 'es-AR'
   when 12289 then 'ar-LB'
   when 12297 then 'en-ZW'
   when 12298 then 'es-EC'
   when 13313 then 'ar-KW'
   when 13321 then 'en-PH'
   when 13322 then 'es-CL'
   when 14337 then 'ar-AE'
   when 14346 then 'es-UY'
   when 15361 then 'ar-BH'
   when 15370 then 'es-PY'
   when 16385 then 'ar-QA'
   when 16394 then 'es-BO'
   when 17418 then 'es-SV'
   when 18442 then 'es-HN'
   when 19466 then 'es-NI'
   when 20490 then 'es-PR'
   else 'en-US'
  end
 select @s1 = dbo.fn_GetNumberFormatString(0, @NumberGroupFormat, @NegativeFormatCode, 0, default, default)
 select @s2 = dbo.fn_GetNumberFormatString(1, @NumberGroupFormat, @NegativeFormatCode, 0, default, default)
 select @s3 = dbo.fn_GetNumberFormatString(2, @NumberGroupFormat, @NegativeFormatCode, 0, default, default)
 select @s4 = dbo.fn_GetNumberFormatString(3, @NumberGroupFormat, @NegativeFormatCode, 0, default, default)
 select @s5 = dbo.fn_GetNumberFormatString(4, @NumberGroupFormat, @NegativeFormatCode, 0, default, default)
 select @s6 = dbo.fn_GetNumberFormatString(5, @NumberGroupFormat, @NegativeFormatCode, 0, default, default)
 
 select @s7 = dbo.fn_GetNumberFormatString(0, @NumberGroupFormat, @NegativeCurrencyFormatCode, 1, @CurrencySymbol, @CurrencyFormatCode)
 select @s8 = dbo.fn_GetNumberFormatString(1, @NumberGroupFormat, @NegativeCurrencyFormatCode, 1, @CurrencySymbol, @CurrencyFormatCode)
 select @s9 = dbo.fn_GetNumberFormatString(2, @NumberGroupFormat, @NegativeCurrencyFormatCode, 1, @CurrencySymbol, @CurrencyFormatCode)
 select @s10 = dbo.fn_GetNumberFormatString(3, @NumberGroupFormat, @NegativeCurrencyFormatCode, 1, @CurrencySymbol, @CurrencyFormatCode)
 select @s11 = dbo.fn_GetNumberFormatString(4, @NumberGroupFormat, @NegativeCurrencyFormatCode, 1, @CurrencySymbol, @CurrencyFormatCode)
 select @s12 = dbo.fn_GetNumberFormatString(5, @NumberGroupFormat, @NegativeCurrencyFormatCode, 1, @CurrencySymbol, @CurrencyFormatCode)
 insert 
  @FormatStrings
 values(
  @DateFormatString,
  @TimeFormatString,
  @NumberLanguageCode,
  @CalendarType,
  @s1, 
  @s2,
  @s3,
  @s4,
  @s5,
  @s6,
  @s7,
  @s8,
  @s9,
  @s10,
  @s11,
  @s12
 )
 return
end
go
declare @target_collation sysname
set @target_collation = 'Latin1_General_CI_AI'
-- a table of 'constraint drop' commands
create table #keydrops 
(
 id int identity primary key, -- orders the rows
 sql nvarchar(4000)    -- contains the command text
)
 
-- a table of 'constraint add' commands
-- (must be calculated before the constraints are dropped)
create table #keymakes
(
 id int identity primary key, -- orders the rows
 sql nvarchar(4000),    -- contains the command text
 ord int       -- groups the commands 
)
-- a table of 'alter table alter column' commands
create table #tablechanges
(
 id int identity primary key, -- orders the rows
 sql nvarchar(4000)    -- contains the command text
)
declare @sql nvarchar(4000)
declare @column nvarchar(131) -- 128+3
declare @i int
-- Step 1 generate drop and create index statements
declare @tablename sysname
declare @indexname sysname
declare @indid int
declare @is_unique_index nvarchar(16)
declare index_cursor cursor for 
select distinct sysobjects.name, sysobjects.uid, sysindexes.name, sysindexes.indid,
 case 
  when sysindexes.status & 2 = 2 then 'UNIQUE '
  else ''
 end
from sysindexes
 join sysindexkeys on (sysindexes.id = sysindexkeys.id
   and sysindexes.indid = sysindexkeys.indid)
 join sysobjects on (sysobjects.id = sysindexes.id)
 join syscolumns on (sysindexkeys.colid = syscolumns.colid and sysobjects.id = syscolumns.id)
 join systypes on (systypes.xtype = syscolumns.xtype and systypes.xtype = systypes.xusertype)
where
 sysobjects.xtype = 'U' 
 and INDEXPROPERTY(sysobjects.id, sysindexes.name, 'IsStatistics') = 0
 and sysindexes.name not in 
  (select name from sysobjects where xtype = 'PK' or xtype = 'F ' or xtype = 'UQ')
 and (systypes.name = 'nvarchar' or systypes.name = 'nchar') 
 and syscolumns.collation is not null
 and syscolumns.collation != @target_collation
declare @tableschemaid int
declare @metadataSchemaId int
set @metadataSchemaId = CONVERT(int, OBJECTPROPERTYEX(OBJECT_ID(N'MetadataSchema.Attribute'),'SchemaId'))
open index_cursor
fetch next from index_cursor into @tablename, @tableschemaid, @indexname, @indid, @is_unique_index
while (@@fetch_status = 0)
begin
 if (@tableschemaid = @metadataSchemaId)
 begin
  set @tablename = N'MetadataSchema.' + @tablename
 end
 insert into #keydrops (sql) values('DROP INDEX ' + @tablename + '.' + @indexname)
 
 select @sql = N'CREATE ' + @is_unique_index + 'INDEX ' + @indexname + N' ON ' + @tablename + N'('
   select @column = index_col(@tablename, @indid, 1)
 set @sql = @sql + @column
    select @i = 2
   select @column = index_col(@tablename, @indid, @i)
    while (@column is not null)
    begin
  set @sql = @sql + ',' + @column
        select @i = @i + 1
     select @column = index_col(@tablename, @indid, @i)
    end    
 set @sql = @sql + N')'
 insert into #keymakes (sql, ord) values(@sql, 1)
    fetch next from index_cursor into @tablename, @tableschemaid, @indexname, @indid, @is_unique_index
end
close index_cursor
deallocate index_cursor
-- Step 2 generate pk drop and pk create statement
declare @pkname sysname
declare pk_cursor cursor for 
select distinct parent.name, sysobjects.name, sysindexes.indid
 from sysobjects 
 join sysobjects as parent on (parent.id = sysobjects.parent_obj)
 join sysindexes on (sysobjects.name = sysindexes.name)
 join sysindexkeys on (sysindexes.id = sysindexkeys.id
   and sysindexes.indid = sysindexkeys.indid)
 join syscolumns on (sysindexkeys.colid = syscolumns.colid and parent.id = syscolumns.id)
 join systypes on (systypes.xtype = syscolumns.xtype and systypes.xtype = systypes.xusertype)
where 
 sysobjects.xtype = 'PK'
 and parent.xtype = 'U' 
 and (systypes.name = 'nvarchar' or systypes.name = 'nchar') 
 and syscolumns.collation is not null
 and syscolumns.collation != @target_collation 
open pk_cursor
fetch next from pk_cursor into @tablename, @pkname, @indid
while (@@fetch_status = 0)
begin
 insert into #keydrops (sql) values('ALTER TABLE ' + @tablename + ' DROP CONSTRAINT ' + @pkname)
 select @sql = N'ALTER TABLE ' + @tablename + N' ADD CONSTRAINT ' + @pkname + ' PRIMARY KEY('
   select @column = index_col(@tablename, @indid, 1)
 set @sql = @sql + @column
    select @i = 2
   select @column = index_col(@tablename, @indid, @i)
    while (@column is not null)
    begin
  set @sql = @sql + ',' + @column
        select @i = @i + 1
     select @column = index_col(@tablename, @indid, @i)
    end    
 set @sql = @sql + N')'
 insert into #keymakes (sql, ord) values(@sql, 2)
    fetch next from pk_cursor into @tablename, @pkname, @indid
end
close pk_cursor
deallocate pk_cursor
-- Step 3 generate UNIQUE CONSTRAINT drop and UNIQUE CONSTRAINT create statement
declare @ucname sysname
declare uc_cursor cursor for 
select distinct parent.name, sysobjects.name, sysindexes.indid
 from sysobjects 
 join sysobjects as parent on (parent.id = sysobjects.parent_obj)
 join sysindexes on (sysobjects.name = sysindexes.name)
 join sysindexkeys on (sysindexes.id = sysindexkeys.id
   and sysindexes.indid = sysindexkeys.indid)
 join syscolumns on (sysindexkeys.colid = syscolumns.colid and parent.id = syscolumns.id)
 join systypes on (systypes.xtype = syscolumns.xtype and systypes.xtype = systypes.xusertype)
where 
 sysobjects.xtype = 'UQ'
 and (systypes.name = 'nvarchar' or systypes.name = 'nchar') 
 and syscolumns.collation is not null
 and syscolumns.collation != @target_collation 
open uc_cursor
fetch next from uc_cursor into @tablename, @ucname, @indid
while (@@fetch_status = 0)
begin
    insert into #keydrops (sql) values('ALTER TABLE ' + @tablename + ' DROP CONSTRAINT ' + @ucname)
    select @sql = N'ALTER TABLE ' + @tablename + ' ADD CONSTRAINT ' + @ucname + N' UNIQUE ('       
   select @column = index_col(@tablename, @indid, 1)
 set @sql = @sql + @column
    select @i = 2
   select @column = index_col(@tablename, @indid, @i)
    while (@column is not null)
    begin
  set @sql = @sql + ',' + @column
        select @i = @i + 1
     select @column = index_col(@tablename, @indid, @i)
    end    
 set @sql = @sql + N')'
 insert into #keymakes (sql, ord) values(@sql, 2)
    fetch next from uc_cursor into @tablename, @ucname, @indid
end
close uc_cursor
deallocate uc_cursor
-- Step 4: for every column in every table with a mismatched collation
-- issue an alter column command
insert into #tablechanges (sql)
 select 'ALTER TABLE ' +
  case
   when sysobjects.uid = @metadataSchemaId then 'MetadataSchema.' + sysobjects.name
   else sysobjects.name
  end
  +   ' ALTER COLUMN ' + syscolumns.name + 
  ' ' + systypes.name + 
  case 
   when systypes.name = 'ntext' then ' COLLATE '
   else 
    case
     when systypes.name = 'nvarchar' and syscolumns.length = -1 then '(max) COLLATE '
     else '(' + cast(syscolumns.length/2 as nvarchar(50)) + ') COLLATE ' 
    end
  end
   +  @target_collation +    
  case 
   when syscolumns.isnullable = 0 then ' NOT NULL'
   else ' NULL' 
  end  
 from syscolumns 
  join sysobjects on (sysobjects.id = syscolumns.id)
  join systypes on (systypes.xtype = syscolumns.xtype and systypes.xtype = systypes.xusertype)
 where
  syscolumns.collation is not null
  and syscolumns.collation != @target_collation
  and sysobjects.type = 'U'
  and (systypes.name = 'nvarchar' or systypes.name = 'nchar' or systypes.name = 'ntext')
order by sysobjects.name, syscolumns.name
-- STEP 5: execute key drops
declare keydrops_cursor cursor for select sql from #keydrops order by id
open keydrops_cursor
fetch next from keydrops_cursor into @sql
while (@@fetch_status = 0)
begin
   print @sql
   exec (@sql)
   fetch next from keydrops_cursor into @sql
end
close keydrops_cursor
deallocate keydrops_cursor
-- STEP 6: execute table changes
declare tables_cursor cursor for select sql from #tablechanges order by id
open tables_cursor
fetch next from tables_cursor into @sql
while (@@fetch_status = 0)
begin
   print @sql
   begin try
  exec (@sql)
 end try
 begin catch
  print 'error executing: ' + @sql
  print ERROR_MESSAGE()
 end catch
   fetch next from tables_cursor into @sql
end
close tables_cursor
deallocate tables_cursor
-- STEP 7: execute key makes
declare keymakes_cursor cursor for select sql from #keymakes order by ord desc, id asc
open keymakes_cursor
fetch next from keymakes_cursor into @sql
while (@@fetch_status = 0)
begin
   print @sql
   exec (@sql)
   fetch next from keymakes_cursor into @sql
end
close keymakes_cursor
deallocate keymakes_cursor
drop table #keydrops
drop table #keymakes
drop table #tablechanges
To be continued...
10 jaar geleden
