一勞永逸的資料庫升級方案
資料庫升級方案
一、面臨的問題
在專案中資料庫升級是經常遇到的事情,這個工作比較繁瑣,特別是線上資料庫升級需要十分小心,我們先來看一下通常面臨的問題:
1、 表修改,包括增加了欄位、修改了欄位型別或者長度,更換了主鍵等。對於表的升級不能刪除重建,需要單獨修改,或者寫指令碼來升級。
2、 檢視的修改,檢視的修改比較簡單,無非是增加了欄位,取消了欄位,不影響基礎資料。檢視的升級可以刪除重建。
3、 儲存過程的修改,儲存過程的修改和檢視一樣,可以刪除重建,二者都可以通過指令碼來完成。
4、 函式的修改,如果專案中用到了函式,函式的升級和儲存過程一樣,不再贅述。
5、 上述情況基本能涵蓋了大部分的資料庫升級的情景,這些工作可以在資料庫管理工具中完成,也可編寫指令碼來完成。我想說的問題並不是這個,而是有時候我們不知道那個表,那個欄位修改了,除非你每改一個地方都做好記錄,儘管如此,在升級的時候也難免落下。
我們公司有一套開發平臺、由此平臺開發了一套進銷存,一套oa系統,而進銷存又延伸出兩套行業版進銷存:鞋服通和醫藥通,以上產品有興趣的可以去官網www.hfbpm.com試用,產品線如下圖:
資料庫和基礎功能都是繼承的,即進銷存使用開發平臺中的表,醫藥通和鞋服通使用通用進銷存中的表,oa使用開發平臺中的表,那麼它們之間的資料庫升級就非常頻繁,剛開靠手工記錄改動的地方,針對性的升級,後來發現工作量非常大,而且經常出錯。
有沒有一個一勞永逸的辦法,比較差異進行資料庫升級?只要思想不滑坡辦法總比困難多!
辦法肯定是有的。
二、解決方案
要解決資料庫升級,主要是解決針對表、檢視、儲存過程函式的升級,後面三個相對來說比較簡單,直接刪除重建即可,難點是如何獲取三者的建立指令碼?只要獲取到完整的指令碼,當做sql語句執行即可,mssqlServer也給出了方法(下面會具體介紹)。表的升級相對來說要麻煩一些,因為表不能刪除重建,必須對列、主鍵、約束等逐項進行比較升級,對於新建的表沒有提供獲取建立表指令碼的方法,需要自己來處理。
下面詳細介紹升級過程。
1、 表建立
MsSqlServer沒有提供獲取建立表指令碼的方法,需要自己根據列屬性生成建立指令碼,為此我們編寫了一個儲存過程Sys_TableScript_MSSQL來做這件事情,儲存過程的程式碼如下圖:
由於篇幅限制,詳細程式碼就不貼出來了,這個方法也是從部落格園裡收到的,稍微改動了一下,執行後輸出的結果如下:
獲取的是一個完整的建立表的指令碼,該腳本當做普通的sql語句執行即可。
2、表升級
當表已經存在時,針對列進行升級,如果列不存在直接建立,如果列存在,那麼是否升級判斷依據是長度、型別、小數點位數、允許為空、預設值是否發生改變,上述只要有其一發生變化就要升級。
建立列的sql指令碼,如下:
ALTER TABLE 表名 ADD 列名 型別 not null default '預設值'
例如
ALTER TABLE dx_ZhiBan ADD leaderName varchar(50) not null default '未填'
如果列已經存在需要使用修改列的sql指令碼,如下:
ALTER TABLE 表名 alter column 列名 型別 not null
例如
alter table dx_ZhiBan alter column Leader nvarchar(50) not null
修改列時如果修改預設值,修改列的指令碼不支援直接修改預設值,因為列一旦建立了預設值,那麼就建立了一個約束,需要先刪除這個約束,再重新建立預設值。刪除預設值約束需要先找到預設值約束的名字,再執行刪除約束指令碼。查詢預設值約束的sql指令碼如下:
select c.name from sysconstraints a inner join syscolumns b on a.colid=b.colid inner join sysobjects c on a.constid=c.id where a.id=object_id('表名') and b.name='列名'
找到約束的名字如下圖:
刪除預設值約束的sql指令碼如下圖:
alter table 表名 drop constraint 預設值約束名
例如:
alter table dx_ZhiBan drop constraint DF__dx_ZhiBan__Leade__3FE65219
刪除預設值後,再執行建立預設值的sql指令碼,如下:
alter table 表名 add default '預設值' for 列名 with values
例如:
alter table dx_ZhiBan add default '未填' for Leader with values
表的升級除了列還包括主鍵,主鍵的升級和預設值類似(因為他們都屬於約束),需要先刪除原來,再建立新的。查詢主鍵約束的sql指令碼如下:
Select name from sysobjects where Parent_Obj=OBJECT_ID('表名') and xtype='PK'
例如:
Select name from sysobjects where Parent_Obj=OBJECT_ID('dx_ZhiBan') and xtype='PK'
查詢結果如下:
刪除主鍵約束的sql指令碼如下:
Alter table dx_ZhiBan Drop PK_dx_ZhiBan
建立主鍵的sql指令碼如下:
ALTER TABLE dx_ZhiBan ADD PRIMARY KEY (ID, leader )
注意,聯合主鍵用逗號分隔,另外,需要說明的是在升級之前要判斷主鍵是否需要升級,如果主鍵沒有變化就不需要升級。
3、檢視升級
檢視升級過程較簡單,刪除掉重新建立即可。刪除檢視的sql指令碼如下:
drop view 檢視名
獲取檢視建立指令碼的sql指令碼,如下:
EXEC sp_helptext @objname='檢視名稱'
執行後結果如下圖:
獲取到該指令碼後,當做普通的sql語句執行即可。
4、儲存過程、函式升級
二者的升級和檢視類似,不再贅述,不同的是刪除儲存過程的sql指令碼是:
drop procedure 儲存過程名
刪除函式的sql指令碼是:
drop function 函式名
5、資料庫升級工具
資料庫的升級是都能通過sql指令碼來完成的,把這些指令碼管理起來需要藉助程式來完成,我們使用net的WinForm來編寫程式。如下圖:
使用這個工具可以選擇那些物件需要升級(沒有勾選的不升級),升級的時候能看到進度和升級結果。
本方案並不是十全十美的,有些問題還沒解決,例如列名稱修改、如何刪除多餘的列等。其他不當之處歡迎大家留言指