因為在系統中,一個業務資料庫往往存在多份物理資料庫,比如開發資料庫,測試資料庫和生產資料庫,加上還有一些其它用途的資料庫,要維持這些資料庫之間的結構統一也不是很容易,所以自己弄了個簡單的資料庫表結構對比程式,用來分析各個資料庫之間的差異.這裡只是簡單的比較,其實在這個基礎上還可以做差異自動修複.下面是代碼:
/建立一個對比結果資料集,兩列,結果含義為: //第1列,第2列 含義 // 空 非空 第2列所示表欄位在第1個資料庫中不存在 // 非空 空 第1列所示表欄位在第2個資料庫中不存在 // 非空 非空 兩個資料庫表和欄位相同,但資料類型有差異 // 空 空 表示兩個資料庫中表和欄位可以對應,但這類結果不儲存. DataTable theTable = new DataTable(); theTable.Columns.Add(new DataColumn("Database1",typeof(string))); theTable.Columns.Add(new DataColumn("Database2",typeof(string))); //擷取Oracle中所有目前使用者擁有的表和欄位名,及其資料類型和資料長度,這裡沒有考慮精度,注意一定要排序,否則必對演算法比較麻煩. string theSQL =@"select t2.TNAME,t1.COLUMN_NAME,t1.DATA_TYPE,t1.DATA_LENGTH from user_tab_columns t1,tab t2 where t1.TABLE_NAME = t2.tname and t2.tabtype='TABLE' order by t2.tname,t1.COLUMN_NAME"; //DataHelper.QueryDataFromDb()就是簡單的查詢語句執行,這個函數很簡單. DataTable theTabs1 = DataHelper.QueryDataFromDb(theSQL, "資料庫連接串"); DataTable theTabs2 = DataHelper.QueryDataFromDb(theSQL, "資料庫連接串"); int theCount1=0; int theCount2 = 0; //進行比對. while (theCount1 < theTabs1.Rows.Count && theCount2 < theTabs2.Rows.Count ) { DataRow theRow1 = theTabs1.Rows[theCount1]; DataRow theRow2 = theTabs2.Rows[theCount2]; string theTabName1 = theRow1["TNAME"].ToString(); string theCol1 = theRow1["COLUMN_NAME"].ToString(); string theType1 = theRow1["DATA_TYPE"].ToString(); int theLen1 = int.Parse(theRow2["DATA_LENGTH"].ToString()); string theTabName2 = theRow2["TNAME"].ToString(); string theCol2 = theRow2["COLUMN_NAME"].ToString(); string theType2 = theRow2["DATA_TYPE"].ToString(); int theLen2 = int.Parse(theRow2["DATA_LENGTH"].ToString()); int theRet1 = String.Compare(theTabName1,theTabName2); //先比對錶,如果表名不相等,因為已經排序,則說明“小的”在另外一方資料中不存在,小的一方索引增加. //如果相等則繼續比較欄位. if(theRet1 > 0) { DataRow theRetRow = theTable.NewRow(); theTable.Rows.Add(theRetRow); theRetRow[1] = "\r\n"+theTabName2+" " + theCol2; theCount2++; continue; } if(theRet1<0) { DataRow theRetRow = theTable.NewRow(); theTable.Rows.Add(theRetRow); theRetRow[0] = "\r\n"+theTabName1+" " + theCol1; theCount1++; continue; } //表名相同,比較欄位,因為已經排序,則說明欄位“小的”在另外一方資料中不存在,小的一方索引增加. //如果相等則繼續比較資料類型和資料長度. int theRet2 = String.Compare(theCol1,theCol2); if(theRet2 > 0) { DataRow theRetRow = theTable.NewRow(); theTable.Rows.Add(theRetRow); theRetRow[1] = "\r\n"+theTabName2+" " + theCol2; theCount2++; continue; } if(theRet2<0) { DataRow theRetRow = theTable.NewRow(); theTable.Rows.Add(theRetRow); theRetRow[0] = "\r\n"+theTabName1+" " + theCol1; theCount1++; continue; } //如果類型或者長度不一致,則都輸出。 if ( theType1 != theType2 || theLen1 != theLen2) { DataRow theRetRow = theTable.NewRow(); theTable.Rows.Add(theRetRow); theRetRow[0] = "\r\n"+theTabName1+" " + theCol1+" "+theType1+" "+theLen1.ToString(); theRetRow[1] = "\r\n"+theTabName2+" " + theCol2+" "+theType2+" "+theLen2.ToString(); } theCount1++; theCount2++; } //這種對比方式下,會產生一方已經到頭,另一方還存在未比對的資料,則只要直接輸出即可。 while (theCount1 < theTabs1.Rows.Count) { DataRow theRetRow = theTable.NewRow(); theTable.Rows.Add(theRetRow); DataRow theRow1 = theTabs1.Rows[theCount1]; theRetRow[0] = "\r\n" + theRow1["TNAME"].ToString() + " " + theRow1["COLUMN_NAME"].ToString(); theCount1++; } while (theCount2 < theTabs1.Rows.Count) { DataRow theRetRow = theTable.NewRow(); theTable.Rows.Add(theRetRow); DataRow theRow2 = theTabs1.Rows[theCount2]; theRetRow[1] = "\r\n" + theRow2["TNAME"].ToString() + " " + theRow2["COLUMN_NAME"].ToString(); theCount2++; }//與資料庫打交道,這裡我用的是odp.net. public class DataHelper { public static DataTable QueryDataFromDb(string Sql, string ConnStr) { OracleConnection theConn = new OracleConnection(ConnStr); OracleDataAdapter theDA = new OracleDataAdapter(Sql, theConn); DataSet theDs = new DataSet(); theDA.Fill(theDs); theDA.Dispose(); theConn.Close(); return theDs.Tables[0]; } }
PS:其實從這個小程式也可以看出排序的重要性,因為資料一旦排序,很多處理就非常方便。如果兩邊結果都沒有排序的話,時間複雜度會很高。上述演算法的時間複雜度為O(m+n).如果沒有排序,就可能達到o(m*n).