因为在系统中,一个业务数据库往往存在多份物理数据库,比如开发数据库,测试数据库和生产数据库,加上还有一些其它用途的数据库,要维持这些数据库之间的结构统一也不是很容易,所以自己弄了个简单的数据库表结构对比程序,用来分析各个数据库之间的差异.这里只是简单的比较,其实在这个基础上还可以做差异自动修复.下面是代码:
/建立一个对比结果数据集,两列,结果含义为:
//第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).