Hope-Faith咖啡屋

博客园 首页 联系 订阅 管理

 

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

2012-5-10 PS

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

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

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
posted on 2010-04-26 15:58  cpmu  阅读(13113)  评论(19编辑  收藏  举报