比较两个DataTable数据(结构相同)——5万条数据仅需几秒

 

最近项目上有一个功能,要求是实时采集和更新可售商品记录。可售商品信息来源于另外一套销售系统的接口。
通常可售商品记录在8万条左右,采集的数据不提供主键,按照一系列的字段内容识别是否相同,好多字段为null值。(所以无法进行主键比较)
采集和保存的业务规则是:
从采集的数据中对照数据库中,采集的数据中存在而库中不存在的商品,属于新增加的商品记录,需要增加到库中。
而库中存在但采集的数据中不存在的,则属于已经销售的商品,需要从库中删除。
为此查阅了很多xdjm的代码,给出了若干解决方法。
可惜在数据量很小的情况还行,当使用实际数据进行时,对照时间已经不能忍受。
于是只能苦思冥想,自行写出了一个方法,贴出来供大家研究,如果发现有bug,请及时告知。

2012-5-10 PS

很感谢一直以来关注本帖的朋友们,原来的代码不是很完善,后来修改了也一直不曾更新,换了个思路重构了代码,如果发现有误请留言。

新代码解决了现有的几个bug,也接受了一些朋友的建议,未经测试,请检查后使用。 

ExpandedBlockStart.gif View Code 
  1          ///   <summary>
  2           ///  比较两个DataTable数据(结构相同,字段名不同)
  3           ///   </summary>
  4           ///   <param name="dtDest"> 来自数据库的DataTable </param>
  5           ///   <param name="dtSrc"> 来自文件的DataTable </param>
  6           ///   <param name="dtRetAdd"> 新增数据(dt2中的数据) </param>
  7           ///   <param name="dtRetDel"> 删除的数据(dt2中的数据) </param>
  8           ///   <param name="srcKeyFields"> 源关键字段名 </param>
  9           ///   <param name="destKeyFields"> 目标关键字段名,与源关键字段名对应 </param>
 10           public  static  void CompareDt(DataTable dtSrc, DataTable dtDest,  out DataTable dtRetAdd,  out DataTable dtRetDel,  string srcKeyFields,  string destKeyFields)
 11         {
 12              // 源记录集与目标记录集有一个为null则退出
 13               if (dtSrc ==  null || dtDest ==  null)
 14             {
 15                 dtRetDel =  null;
 16                 dtRetAdd =  null;
 17                  return;
 18             }
 19              // 定义返回记录表
 20              dtRetDel = dtSrc.Clone();
 21             dtRetAdd = dtRetDel.Clone();
 22              // 参照列为空则退出
 23               if ( string.IsNullOrEmpty(srcKeyFields) ||  string.IsNullOrEmpty(destKeyFields))
 24                  return;
 25              // 获得参照列列表
 26               string[] srcFields = srcKeyFields.Split( ' , '); // 列名数组
 27               string[] destFields = destKeyFields.Split( ' , '); // 列名数组
 28               // 参照列数目不一致则退出
 29               if (srcFields.Length != destFields.Length)
 30                  return;
 31              // 按参照列排序源表和目标表
 32              DataRow[] drSrc = dtSrc.Select( "", srcKeyFields);
 33             DataRow[] drDest = dtDest.Select( "", destKeyFields);
 34              // 定义源表和目标表长度
 35               int iSrcCount = drSrc.Length;
 36              int iDestCount = drDest.Length;
 37              // 源表为空则目标表全部加入删除队列并返回
 38               if (iSrcCount ==  0)
 39             {
 40                  foreach (DataRow row  in drDest)
 41                 {
 42                     dtRetDel.Rows.Add(row.ItemArray);
 43                 }
 44                  return;
 45             }
 46              // 目标表为空则源表全部加入新增队列并返回
 47               if (iDestCount ==  0)
 48             {
 49                  foreach (DataRow row  in drSrc)
 50                 {
 51                     dtRetAdd.Rows.Add(row.ItemArray);
 52                 }
 53                  return;
 54             }
 55              // 定义源表和目标表指针
 56               int iSrc =  0;
 57              int iDest =  0;
 58              // 开始循环比对
 59               while (iSrc < iSrcCount && iDest < iDestCount)
 60             {
 61                  // 定义列比对结果
 62                   int result =  0;
 63                  object oSrc;
 64                  object oDest;
 65                  // 循环比对列值
 66                   for ( int colIndex =  0; colIndex < srcFields.Length; colIndex++)
 67                 {
 68                      // 获得列值
 69                      oSrc = drSrc[iSrc][srcFields[colIndex]];
 70                     oDest = drDest[iDest][destFields[colIndex]];
 71                      // 比较列值,不相等则退出循环
 72                       if (oSrc == DBNull.Value)
 73                     {
 74                         result = oDest == DBNull.Value ?  0 : - 1;
 75                     }
 76                      else
 77                     {
 78                         result = oDest == DBNull.Value ?  1 :  string.Compare(oSrc.ToString(), oDest.ToString(),  false);
 79                     }
 80                      if (result !=  0)
 81                          break;
 82                 }
 83                  // 检查行比较结果
 84                   switch (result)
 85                 {
 86                      /// /源表小则将源表本行加入新增队列,同时移动源表指针
 87                       case - 1:
 88                         dtRetAdd.Rows.Add(drSrc[iSrc].ItemArray);
 89                         iSrc++;
 90                          break;
 91                      /// /相同两表同时移动指针
 92                       case  0:
 93                         iSrc++;
 94                         iDest++;
 95                          break;
 96                      /// /目标表小则将目标表本行加入删除队列,同时移动目标表指针
 97                       case  1:
 98                         dtRetDel.Rows.Add(drDest[iDest].ItemArray);
 99                         iDest++;
100                          break;
101                      default:
102                          break;
103                 }
104             }
105              // 源表到达最后一条,目标表未到达,则目标表剩余行全部加入删除队列
106               if (iDest < iDestCount)
107             {
108                  for ( int index = iDest; index < iDestCount; index++)
109                 {
110                     dtRetDel.Rows.Add(drDest[index].ItemArray);
111                 }
112             }
113              // 目标表到达最后一条,源表未到达,则源表剩余行全部加入新增队列
114               else  if (iSrc < iSrcCount)
115             {
116                  for ( int index = iSrc; index < iSrcCount; index++)
117                 {
118                     dtRetAdd.Rows.Add(drSrc[index].ItemArray);
119                 }
120             }
121

转载于:https://www.cnblogs.com/cpmu/archive/2010/04/26/1721298.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值