{"id":82103,"date":"2011-04-08T23:36:36","date_gmt":"2011-04-08T23:36:36","guid":{"rendered":"https:\/\/www.webstaging.red-gate.com\/simple-talk\/?p=73364"},"modified":"2018-12-12T12:11:45","modified_gmt":"2018-12-12T12:11:45","slug":"the-process-of-changing-the-collation-for-a-database-and-objects","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/blogs\/the-process-of-changing-the-collation-for-a-database-and-objects\/","title":{"rendered":"The Process of Changing the Collation For a Database and Objects"},"content":{"rendered":"<p><em>Note: This is a \u201cclassic\u201d post lightly edited that I wrote a while back and a reader asked about it. It has nothing to do with the fact that LaRock downgraded my status on his site: <\/em><a title=\"http:\/\/thomaslarock.com\/rankings\/\" href=\"http:\/\/thomaslarock.com\/rankings\/\"><em>http:\/\/thomaslarock.com\/rankings\/<\/em><\/a><\/p>\n<p>The scenario that got me started on this path was that one of our servers was installed with the default &quot;old faithful&quot; SQL_Latin1_General_CP1_CI_AS collation, and the main servers were in a Windows collation Latin1_General_CI_AS based on the suggestion when installing Microsoft CRM many years ago.&#160; Note too that if you have any columns that you specifically want in a different collation than the rest of the database, of any collations coded in your code you will need to manage that yourself.<\/p>\n<p>I do the process using the following simple, yet time consuming, process.&#160; Simple might be a misstatement.&#160; Perhaps straightforward:   <br \/>&#160; <br \/><strong>1.&#160; Make a copy\/script of the database, in a manner that does not specify collations.<\/strong>&#160; I will be using Red-Gate SQL Compare for this task because it can remove collation information from object creation.&#160; I use their snapshot capabilities to create a code only copy of the database.&#160; If you have build scripts for your database that don&#8217;t include table drops\/creates, but have all constraints, that is as good too.&#160; Currently I don&#8217;t know of a good tool to selectively script parts of a database (like all checks, defaults, etc without tables.&#160; And I am a fan of the Red-Gate tool anyhow.&#160; For full disclosure, the copy I am using was given to me by Red-Gate as an MVP.&#160; I am not however being paid for an endorsement in any way. )    <br \/>&#160; <br \/><strong>2.&#160; Remove most code and constraints from the database.<\/strong>&#160; I remove all of them using a set of procedures that you can download from <a href=\"http:\/\/drsql.org\/Documents\/utility.drop_objects_procs.zip\">http:\/\/drsql.org\/Documents\/utility.drop_objects_procs.zip<\/a> that you can use to remove most everything from the database.&#160; (I drop CLR objects, but not assemblies and have not done any testing along these lines yet. I have not implemented a procedure for full text objects, so for that you will be on your own&#160; We only have a single full text index in use at this point, so I haven&#8217;t looked into it fully yet.)    <br \/>&#160; <br \/>The procedures are in a utility schema, and they are:    <br \/>&#160; <br \/>utility.relationships$remove      <br \/>utility.checkConstraints$remove       <br \/>utility.defaultConstraints$remove       <br \/>utility.indexes$remove       <br \/>utility.uniqueConstraints$remove       <br \/>utility.primaryKeyConstraints$remove       <br \/>utility.codedObjects$remove &#8211;triggers, stored procedures, the lot can be removed       <br \/>utility.columns$changeCollation       <br \/>utility.computedColumns$remove &#8211;removes computed columns because they are based on columns that we have to change<\/p>\n<p>Each of these has a parameter combination (generally defaults or &#8216;%&#8217; wildcards) that will let you get rid of everything in the database other than tables:   <br \/>&#160; <br \/>exec utility.checkConstraints$remove @table_schema = &#8216;%&#8217;     <br \/>exec utility.defaultConstraints$remove @table_schema = &#8216;%&#8217;      <br \/>exec utility.indexes$remove @table_name = &#8216;%&#8217;,@index_name = &#8216;%&#8217;      <br \/>exec utility.uniqueConstraints$remove @table_schema = &#8216;%&#8217;, @table_name = &#8216;%&#8217;, @index_name = &#8216;%&#8217;      <br \/>exec utility.codedObjects$remove @object_name = &#8216;%&#8217;      <br \/>exec utility.computedColumns$remove @table_name = &#8216;%&#8217;, @column_name = &#8216;%&#8217;, @table_schema = &#8216;%&#8217;<\/p>\n<p>The script I ran to remove objects was basically very much a &quot;dumb&quot; process.&#160; For example, I chose to just drop all indexes rather than only dropping indexes that involved columns with char datatypes.&#160; In the future I might upgrade my index, unique and primary key constraint dropping code to discriminate between rows of different types.&#160; Certainly if I have to do a larger database that is in production (something I luckily never had to do again.)    <br \/>&#160; <br \/>It will not drop computed columns, so you might have to do those drops manually.    <br \/>&#160; <br \/>Note, I didn&#8217;t do foreign keys or primary keys as I use identities for all keys in this database.&#160; Hence they will not be affected by my script, but I do include a relationship drop procedure because I use it daily in a few drop and reload style ETL processes.    <br \/>&#160; <br \/><strong>3.&#160; Change the collations.<\/strong>&#160; To do this, you simply alter each character column setting the new collation in the ALTER COLUMN statement.&#160; This is built into my procedure, so I just run this:    <br \/>&#160; <br \/>exec utility.columns$changeCollation @fromCollation = &#8216;SQL_Latin1_General_CP1_CI_AS&#8217;,    <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; @toCollation = &#8216;Latin1_General_CI_AS&#8217;    <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <br \/>If you have missed anything (like you didn&#8217;t remove coded objects, or you had full-text indexes that you needed to drop), the error handling of the utility procs basically returns the error as a result set, and in that message I include the statement that was tried to be executed.&#160; If I didn&#8217;t screw something up (like the first time I ran it I had messed up the quotename() usage to return [varchar(20)] instead of [varchar](20).&#160; That looks funny, but obviously the other way was thinking it was a user-defined type of &quot;varchar(20)&quot;    <br \/>&#160; <br \/>The procedure basically is a cursor on the following statement    <br \/>&#160; <br \/>Declare @fromCollation sysname,     <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; @toCollation sysname       <br \/>select&#160;&#160; @fromCollation = &#8216;SQL_Latin1_General_CP1_CI_AS&#8217; &#8211;or whatever      <br \/>select&#160;&#160; @toCollation = &#8216;Latin1_General_CI_AI&#8217;&#160; &#8211;or whatever <\/p>\n<p>SELECT &#8216;ALTER TABLE &#8216; + quotename(TABLE_NAME) +     <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#8216; ALTER COLUMN &#8216; + quotename(COLUMN_NAME) + &#8216; &#8216; + quotename(DATA_TYPE) +      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; CASE WHEN CHARACTER_MAXIMUM_LENGTH = -1 then &#8216;(max)&#8217;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHEN DATA_TYPE in (&#8216;text&#8217;,&#8217;ntext&#8217;) then &#8221;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHEN CHARACTER_MAXIMUM_LENGTH IS NOT NULL       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; THEN &#8216;(&#8216;+(CONVERT(VARCHAR,CHARACTER_MAXIMUM_LENGTH)+&#8217;)&#8217; )      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ELSE isnull(CONVERT(VARCHAR,CHARACTER_MAXIMUM_LENGTH),&#8217; &#8216;) END       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; +&#8217; COLLATE &#8216; + @toCollation+ &#8216; &#8216; + CASE IS_NULLABLE      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHEN &#8216;YES&#8217; THEN &#8216;NULL&#8217;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHEN &#8216;No&#8217; THEN &#8216;NOT NULL&#8217;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; END      <br \/>FROM&#160;&#160; INFORMATION_SCHEMA.COLUMNS      <br \/>WHERE DATA_TYPE IN (&#8216;varchar&#8217; ,&#8217;char&#8217;,&#8217;nvarchar&#8217;,&#8217;nchar&#8217;,&#8217;text&#8217;,&#8217;ntext&#8217;)      <br \/>&#160;&#160;&#160; and&#160; COLLATION_NAME like @fromCollation <\/p>\n<p>&#160; <br \/><strong>4.&#160; Change the database collation <\/strong>(or this will be all for naught when people try to create objects and you will have to try again.)    <br \/>&#160; <br \/>alter database &lt;databaseName&gt;      <br \/>&#160;&#160;&#160;&#160; set single_user with rollback immediate      <br \/>go      <br \/>alter database &lt;databaseName&gt;      <br \/>&#160;&#160;&#160;&#160; collate Latin1_General_CI_AS      <br \/>go      <br \/>alter database &lt;databaseName&gt;      <br \/>&#160;&#160;&#160;&#160; set multi_user <\/p>\n<p>&#160; <br \/><strong>5. Now I just run the scripts to recreate all of the objects, or compare the RedGate snapshot, etc.<\/strong>&#160; Make sure that you don&#8217;t include the old collation in any of your scripts\/comparisons, otherwise you will lose all of your hard work \ud83d\ude42    <br \/>&#160; <br \/><strong>6. Finally I drop the utility objects. <\/strong>Then the database is back to where it stared, with different collations for all of the text data.<\/p>\n<p>Good luck!   <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Note: This is a \u201cclassic\u201d post lightly edited that I wrote a while back and a reader asked about it. It has nothing to do with the fact that LaRock downgraded my status on his site: http:\/\/thomaslarock.com\/rankings\/ The scenario that got me started on this path was that one of our servers was installed with&#8230;&hellip;<\/p>\n","protected":false},"author":56085,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[],"coauthors":[19684],"class_list":["post-82103","post","type-post","status-publish","format-standard","hentry","category-blogs"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/82103","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/56085"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=82103"}],"version-history":[{"count":1,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/82103\/revisions"}],"predecessor-version":[{"id":82277,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/82103\/revisions\/82277"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=82103"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=82103"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=82103"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=82103"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}