[急]DataTable的对比问题

heboyi 2007-10-16 04:53:41
有两张DataTable结构一样,其中的数据有差异!
public DataTable Compare(DataTable verNew, DataTable verOld)
表有主键
比较后的结果需要标记出是新增的,修改的,删除的!
...全文
1107 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
LighBlade 2007-10-23
  • 打赏
  • 举报
回复
To heboyi :
你的这种方法请以后不要考虑,try catch 并非是用来做验证的
比如你要判断一个字符串是否是数字,难道用try catch 来做转换
转换成功就是数字吗?

到其他地方搜索下try catch 的真正用途吧

 
private void CompareDataTable(DataTable dtOld, DataTable dtNew)
{
DataRow[] drS; //存放指向旧表相应行的指针
bool bAllTheSame; //存放某行数据是否有所变更的标志
foreach(DataRow dr in dtNew.Rows)
{
drS = dtOld.Select("ID =" + dr["ID"].ToString()); //检索旧表,看是否有对应行
if (drS.Length > 0) //旧表有对应行
{
bAllTheSame = true;
for (int i = 0; i < dtOld.Columns.Count; i++) //看是否某列的值被变更
{
if (dr[i].ToString().CompareTo(drS[0][i].ToString()) != 0) //有变更
{
bAllTheSame = false;
break;
}
}
if (bAllTheSame) //所有列未被变更
{
dr["Status"] = "UnChanged";
drS[0]["Status"] = "UnChanged";
}
else //有些列被变更
{
dr["Status"] = "Modified";
drS[0]["Status"] = "Modified";
}
}
else //旧表中无对应行
{
dr["Status"] = "Added";
}
}//至此,新表标志完毕,旧表只剩删除行未被标志

foreach (DataRow dr in dtOld.Rows)
{
if (dr["Status"].ToString().Length == 0) //旧表中此行数据未被标志
{
dr["Status"] = "Delete";
}
}//至此,旧表删除行标志完毕
}


/*再次解释:drS 数组不开辟新内存,因为是主键检索,所以drS数组只能最多有一条数据
并且修改drS[0]的某列的值,实质上就是修改了dtOld表中相应列的值 */

Cherish20 2007-10-22
  • 打赏
  • 举报
回复
给LZ说说我以前作的思想:
首先在OLD和NEW表中分别增加TimeStamp字段,此字段内容由DB负责。
比较两表时,以NEW表为外循环,依照ID查找OLD表记录,找到再比较TimeStamp字段是否相同同时BREAK此次循环,
如果找不到则为新增。依次操作即可。
anncesky 2007-10-22
  • 打赏
  • 举报
回复
学习
-----
打倒小日本
heboyi 2007-10-22
  • 打赏
  • 举报
回复
已经解决了!
希望还有更好的方法!到期结贴!给出代码的都有分!
        /// <summary>
/// 比较两表
/// </summary>
/// <param name="oldTable">老的版本</param>
/// <param name="newTable">新的版本</param>
/// <param name="primaryKeys">主键</param>
/// <returns>返回的结果中新增changed列标记结果</returns>
private static DataTable CompareDataTable(DataTable oldTable, DataTable newTable, params DataColumn[] primaryKeys)
{
DataTable result = newTable.Copy();
DataColumn[] tdc = new DataColumn[oldTable.Columns.Count];
for (int x = 0; x < oldTable.Columns.Count; x++)
{
tdc[x] = oldTable.Columns[x];
}
result.Columns.Add("changed");

oldTable.PrimaryKey = tdc;
oldTable.Columns.Add("changed");
DataRow dr = oldTable.NewRow();
for (int i = 0; i < newTable.Rows.Count; i++)
{
dr.ItemArray = newTable.Rows[i].ItemArray;
try
{
oldTable.Rows.Add(dr);
//注意:这里Remove以后dr的指针会跑没
oldTable.Rows.Remove(dr);
//因为前面的Remove使dr的指针跑掉了,所以要重新赋一次值
dr.ItemArray = newTable.Rows[i].ItemArray;
oldTable.PrimaryKey = primaryKeys;
try
{
oldTable.Rows.Add(dr);
result.Rows[i]["changed"] = "新增";
}
catch (ConstraintException)
{
result.Rows[i]["changed"] = "修改";
oldTable.Rows[i]["changed"] = "修改";

}
finally
{
oldTable.PrimaryKey = tdc;
}
}
catch (ConstraintException)
{

result.Rows[i]["changed"] = "没有改变";
oldTable.Rows[i]["changed"] = "没有改变";
}
}
foreach (DataRow rd in oldTable.Rows)
{
if (rd["changed"] == DBNull.Value)
{
rd["changed"] = "被删除的";
DataRow nr = result.NewRow();
nr.ItemArray = rd.ItemArray;
result.Rows.Add(nr);
}
}
return result;
}
LighBlade 2007-10-20
  • 打赏
  • 举报
回复
不好意思,非中文系统,拿写字板写的

public DataTable Compare(DataTable dtNew, DataTable dtOld)
{
foreach(DataRow dr in dtNew.Rows)
{
DataRow[] drs = dtOld.Select("PrimaryKey = " + dr["PrimaryKey"].ToString());
if (drs != null) // can match, and there is only one row in drs
{
// compare every column
for(int i=0; i<dtNew.columns.count; i++)
{
drs[0] = dr[i]?
}
// if all the columns is the same
dr["Flag"] = "Unchanged";
drs[0]["Flag"] = "Unchanged";

// if all the columns is not the same
dr["Flag"] = "Modified";
drs[0]["Flag"] = "Modified";
}
else // can't match
{
dr["Flag"] = "Added";
}
}


foreach(DataRow dr in dtOld.Rows)
{
if (dr["Flag"] = null) // not (Modified or Added or Unchanged), there is no flag
{
dr["Flag"] = "Delete";
}
}
}

以上, 对drs[0]的标记,其实就是对dtOld的相应行的标记
drs数组并没有开辟新内存,只是对原有数据行的引用
cpw999cn 2007-10-19
  • 打赏
  • 举报
回复
To:heboyi
删除是判断不出来的,旧表中删除的,新表中有旧表中没有的,对于旧表来说就是新增的,无法判断旧表原来是否有该记录(我想你需要做这种比较就表明你不是直接对旧表的datatable进行操作,否则用不着这样做比较)
LighBlade 2007-10-18
  • 打赏
  • 举报
回复
To :cpw999cn 没细看
但是 for 里 套try
try 里套 try
以catch 获得结果
等等,太耗费系统资源,如非必要(一般不需要),不要这样做
龙宜坡 2007-10-17
  • 打赏
  • 举报
回复
有创意
cpw999cn 2007-10-17
  • 打赏
  • 举报
回复
说明一下,上面代码中Id是主键列,我忘了设,这种方法效率较高,因为不是采用手工比较
而是尝试将新行加入旧表中,从加入的结果进行判断
cpw999cn 2007-10-17
  • 打赏
  • 举报
回复
我用winform做了个小程序,希望对你有帮助

DataTable oldTable = new DataTable();
DataTable newTable = new DataTable();
private void Form1_Load(object sender, EventArgs e)
{
oldTable.Columns.Add("Id", typeof(int));
oldTable.Columns.Add("Name");
oldTable.Rows.Add("1", "一");
oldTable.Rows.Add("2", "二");

newTable.Columns.Add("Id", typeof(int));
newTable.Columns.Add("Name");
newTable.Rows.Add("1", "一");
newTable.Rows.Add("2", "三");
newTable.Rows.Add("3", "二");

MessageBox.Show(dataTableCompare(oldTable, newTable));
}

private string dataTableCompare(DataTable oldTable, DataTable newTable)
{
oldTable.PrimaryKey = new DataColumn[] { oldTable.Columns["Id"], oldTable.Columns["Name"] };
string ret = string.Empty;
DataRow dr = oldTable.NewRow();
for (int i = 0; i < newTable.Rows.Count; i++)
{
dr.ItemArray = newTable.Rows[i].ItemArray;
try
{
oldTable.Rows.Add(dr);

//注意:这里Remove以后dr的指针会跑没
oldTable.Rows.Remove(dr);
//因为前面的Remove使dr的指针跑掉了,所以要重新赋一次值
dr.ItemArray = newTable.Rows[i].ItemArray;
oldTable.PrimaryKey = new DataColumn[] { oldTable.Columns["Id"] };
try
{
oldTable.Rows.Add(dr);

ret += string.Format("新表中的第{0}行是新增的\n", i.ToString());
}
catch
{
ret += string.Format("新表中的第{0}行是修改过的\n", i.ToString());
}
finally
{
oldTable.PrimaryKey = new DataColumn[] { oldTable.Columns["Id"], oldTable.Columns["Name"] };
}
}
catch
{
ret += string.Format("新表中的第{0}行是没有修改过的\n", i.ToString());
}
}
return ret;
}
publina 2007-10-17
  • 打赏
  • 举报
回复
public DataTable Compare(DataTable verNew, DataTable verOld)
{
for (int iRows = 0; iRwos < verOld.Rows.Count; iRows++)
{
DataRow[] drs = verNew.Select("verOld.关键字 = " + verOld.Rows[iRows]["verNew.关键字"].ToString());
if (drs != null)
{
//匹配关键字成功
for (int iItems; iItems < drs.Length; iItems++)
{
//TODO 一个字段一个字段比较罗

}
}
else
{
//匹配关键字失败
//TODO:为新增标记
}
}

//TODO:没有标识就删除
}
cpw999cn 2007-10-17
  • 打赏
  • 举报
回复
如果硬是要这么操作的话,那只能一行行遍历并进行比较了
LighBlade 2007-10-17
  • 打赏
  • 举报
回复
的确如此,如果真的是两个结构相同的表,只能逐行比较
但是如果只是某个表(dtOld)的数据变化了
而你想获得某些变化,那么请用GetChanges 方法

DataTable dtNew = dtOld.GetChanges(DataRowState.Added);
DataTable dtNew = dtOld.GetChanges(DataRowState.Deleted);
DataTable dtNew = dtOld.GetChanges(DataRowState.Detached);
DataTable dtNew = dtOld.GetChanges(DataRowState.Modified);
DataTable dtNew = dtOld.GetChanges(DataRowState.Unchanged);
heboyi 2007-10-17
  • 打赏
  • 举报
回复
还有删除哦!!
heboyi 2007-10-17
  • 打赏
  • 举报
回复
不错参考!
jetxia 2007-10-16
  • 打赏
  • 举报
回复

单就比较两个表的数据的话是没有太好算法

不知道楼主是要处理什么样的业务?
一般在比较或是同步数据的时候,我想应该有一个表作为参考,如果有更新的话做出标记,或是满足一定的条件,只比较更新的数据(更新:增删改)
heboyi 2007-10-16
  • 打赏
  • 举报
回复
字段很多
给出点具体的东西!最好是带注释的代码!
//找出verNew的关键值到verOld中去匹配
//找不到 该条新增 标记
//找到并一致 该条未做任何操作 标记
//找到不一致 该条为修改 标记
//就版本有未标记的内容 为被删除内容
it_mpf 2007-10-16
  • 打赏
  • 举报
回复
一行行比较了,你不是有主键的啊
1、遍历其中旧表,取出当前行主键,然后在另一张表中找,如果找到就再比较内容是不是一样的,如果没找到就说明删掉了
2、然后用上面的方法遍历新表,每一行与旧表的比,如果发现找不到的,则说明是新增的,此时不用再比较内容了,因为前面已经比较过了!

比较SB的办法,我也等等看有没有更好的办法!

110,571

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧