在部署ERP應用時,經常會碰到在開發環境下,沒有問題,部署到服務器上,就出錯。不同語言版本的操作系統、不同的數據庫版本,等等因素的數據庫排序規則的問題。比如在安裝SQL Server 時取默認的規則,中文環境下,會設置為Chinese_PRC_CI_AS,但我們需要的規則應該是SQL_Latin1_General_CP1_CI_AS。在數據操作過程中,這個不一致會導致SQL語句的字符串相等報錯。錯誤語句如下
The default collation of database 'pco' cannot be set to SQL_Latin1_General_CP1_CI_AS.
對於報表的存儲過程,錯誤更嚴重。每個有建立臨時表,比較字符串的地方,都會報錯。
當安裝時設定的SQL Server排序規則為Chinese_PRC_CI_AS,建數據庫時又選定為默認規則,則數據庫的排序規則也是Chinese_PRC_CI_AS,運行如下的腳本把它改變為SQL_Latin1_General_CP1_CI_AS:
Alter database [Database name] collate SQL_Latin1_General_CP1_CI_AS
當數據庫中的Index,Constraint依賴於數據庫排序規則時,上面的語句很難成功運行。
CodeProject上面有一篇文章Easy way to change collation of all database objects in SQL Server
這里的程序以依據這篇文章介紹的原理,開發出來對它封裝一下,簡化操作。
如圖所示的軟件界面,設定SQL Server實例,選取數據庫名字,輸入要改變成的排序規則,點擊處理,即可生成包含7個步驟運行的SQL語句,把這7個SQL語句依次放到數據庫中執行一次,即可改變它的排序規則。
1 Prepare Procedure 准備程序,先要運行一下,以生成創建SQL Server Constraint/Index的腳本。
有五個關鍵的存儲過程要先運行CreateKeyIndex.sql ,DropKeyIndex.sql,ScriptCreateTableKeys.sql,ScriptDropTableKeys.sql,G
enerateDefaultCollation.sql 。目的如它的名字所示,創建索引和約束。
在編程過程,原本是想把這幾個SQL語句直接以SqlCommand的方式發送到SQL Server中去運行,但是它會報一個SQL語句太長的錯誤,求助於Google沒有解決,只好在SQL Server服務器中手動運行這幾個腳本。
后面生成的SQL語句,也都應用此政策(policy),一方面是沒有解決SQL語句太長的問題,另一方面,從效率上來說,直接在SQL Server Management Studio中運行SQL語句的效率是最好的。
2 Drop Key Index 依據數據庫中的所有表刪除所有的Index,生成它如下的例子語句
DROP INDEX [PRCALW_INDEX2] ON [dbo].[WorkCentreCalendar]; DROP INDEX [PRCALW_INDEX0] ON [dbo].[WorkCentreCalendar]; ALTER TABLE [dbo].[WorkCentreCalendar] DROP CONSTRAINT [PRCALW_PK];
3 Change Collation 改變表的排序規則 對字符串字段,它會生成ALTER語句,例子如下
ALTER TABLE [CalendarTemplate] ALTER COLUMN [REF_NO] nvarchar(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ALTER TABLE [CalendarTemplate] ALTER COLUMN [FIRST_DAY] char(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE [CalendarTemplate] ALTER COLUMN [FIRST_SHIFT_BEGIN] nchar(4) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE [CalendarTemplate] ALTER COLUMN [SENCOND_SHIFT_BEGIN] nchar(4) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE [CalendarTemplate] ALTER COLUMN [THIRD_SHIFT_BEGIN] nchar(4) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE [CalendarTemplate] ALTER COLUMN [MON_HOLIDAY] char(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE [CalendarTemplate] ALTER COLUMN [WEN_HOLIDAY] char(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE [CalendarTemplate] ALTER COLUMN [WEN_HALFDAY] char(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
4 Create Key Index 創建主鍵腳本,主要是表的主鍵,在這里重建,例子腳本如下
ALTER TABLE [dbo].[Account] ADD CONSTRAINT [GBACCT_PK] PRIMARY KEY CLUSTERED ( [ACCT_NO] ) WITH ( PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON ) ON [PRIMARY]; CREATE UNIQUE NONCLUSTERED INDEX [GBACCT_INDEX0] ON [dbo].[Account] ( [RECNUM] ) WITH ( PAD_INDEX = OFF, FILLFACTOR = 70, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON ) ON [PRIMARY]; CREATE UNIQUE NONCLUSTERED INDEX [GBACCT_INDEX2] ON [dbo].[Account] ( [ACCT_NAME], [ACCT_NO] ) WITH ( PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON ) ON [PRIMARY];
5 Disable Check Constraint 把Check 約束禁用
Declare @action nvarchar(20) SET @action='Disable' --Enable Disable --Declare @action nvarchar(20) --SET @action='Enable' Declare @sql nvarchar(200) Declare @Name nvarchar(200) Declare @TableName nvarchar(200) Declare Cur Cursor For SELECT name,OBJECT_NAME(parent_object_id) FROM sys.check_constraints Open Cur Fetch next From Cur Into @Name,@TableName While @@fetch_status=0 BEGIN IF @action='Disable' SELECT @sql='alter table ' + @TableName +' NOCHECK CONSTRAINT ' + @Name ELSE SELECT @sql='alter table ' + @TableName +' WITH CHECK CHECK CONSTRAINT ' + @Name Fetch Next From Cur Into @Name,@TableName End Close Cur Deallocate Cur
6 Udpdate Database 這一步驟,看到期待的經典的語句
ALTER DATABASE MIS SET SINGLE_USER WITH ROLLBACK IMMEDIATE ALTER DATABASE MIS COLLATE SQL_Latin1_General_CP1_CI_AS ALTER DATABASE MIS SET ARITHABORT ON ALTER DATABASE MIS SET MULTI_USER
7 Enable Check Constraint 啟用約束,完成數據庫的排序修改動作
Declare @action nvarchar(20) SET @action='Enable' --Enable Disable --Declare @action nvarchar(20) --SET @action='Enable' Declare @sql nvarchar(200) Declare @Name nvarchar(200) Declare @TableName nvarchar(200) Declare Cur Cursor For SELECT name,OBJECT_NAME(parent_object_id) FROM sys.check_constraints Open Cur Fetch next From Cur Into @Name,@TableName While @@fetch_status=0 BEGIN IF @action='Disable' SELECT @sql='alter table ' + @TableName +' NOCHECK CONSTRAINT ' + @Name ELSE SELECT @sql='alter table ' + @TableName +' WITH CHECK CHECK CONSTRAINT ' + @Name Fetch Next From Cur Into @Name,@TableName End Close Cur Deallocate Cur
第5步和第7步使用的SQL語句基本相同,遍歷所有的約束,生成NOCHECK和WITH CHECK的SQL語句。
您可以到CodeProject網站中下載源代碼,文章標題是
Easy way to change collation of all database objects in SQL Server。
剛開始讀這篇文章,有些吃力,消化不了。在Google尋找解決辦法過程中,最后還是覺得他提出的方案是很好的。在這里,我向前走一步,做一個固化的程序來解決問題,讓步驟明了簡明,著文以分享給大家,歡迎指正。