如何通过linq将重复记录合并到一个记录中

时间:2015-02-21 17:07:03

标签: sql linq datatable merge

ID     Name   from       to
001-1  ABC    2015/05/01 2015/05/31
001-1  ABC    2015/06/01 2015/07/15
003-2  DEF    2015/05/01 2015/05/11
002-1  LMN    2015/05/01 2015/06/15
002-1  LMN    2015/06/16 2015/07/31
003-2  DEF    2015/06/01 2015/07/15
004-5  GHI    2015/05/11 2015/05/15

我想将记录合并到一个匹配2015/05/152015/07/15的句点的记录,就像datable中的以下结果一样。

ID     Name   from       to 
001-1  ABC    2015/05/01 2015/07/15  
002-1  LMN    2015/05/01 2015/07/31

003-2004-5不在新数据表中,因为它们不在require范围内。

我怎么能得到这个?我只知道关于LINQ的非常基本的知识,这对我来说非常新鲜。 THX。

1 个答案:

答案 0 :(得分:0)

将此类/数据作为模型:

class Item
{
    public string ID { get; set; }
    public string Name { get; set; }
    public DateTime From { get; set; }
    public DateTime To { get; set; }
}

List<Item> items = new List<Item> {
   new Item { ID = "001-1", Name = "ABC", 
              From = DateTime.Parse("2015/05/01"), 
              To = DateTime.Parse("2015/05/31") },
   new Item { ID = "001-1", Name = "ABC", 
              From = DateTime.Parse("2015/06/01"), 
              To = DateTime.Parse("2015/07/15") },
   new Item { ID = "003-2", Name = "DEF", 
              From = DateTime.Parse("2015/05/01"), 
              To = DateTime.Parse("2015/05/11") },
   new Item { ID = "002-1", Name = "LMN", 
              From = DateTime.Parse("2015/05/01"), 
              To = DateTime.Parse("2015/06/15") },
   new Item { ID = "002-1", Name = "LMN", 
              From = DateTime.Parse("2015/06/16"), 
              To = DateTime.Parse("2015/07/31") },
   new Item { ID = "003-2", Name = "DEF", 
              From = DateTime.Parse("2015/06/01"), 
              To = DateTime.Parse("2015/07/15") },
   new Item { ID = "004-5", Name = "GHI", 
              From = DateTime.Parse("2015/05/11"), 
              To = DateTime.Parse("2015/05/15") }
            };

您可以使用以下linq查询来获取所需的结果集:

  var result = from i in items
               orderby i.From
               group i by new { i.ID, i.Name } into iGroup
               where iGroup.First().From <= DateTime.Parse("2015/05/15") && 
                     iGroup.Last().To >= DateTime.Parse("2015/07/1") &&
                     (iGroup.Last().To - iGroup.First().From).Days + 1 == 
                        iGroup.Sum(g => (g.To - g.From).Days + 1)
               select new Item
               {
                  ID = iGroup.Key.ID,
                  Name = iGroup.Key.Name,
                  From = iGroup.First().From,
                  To = iGroup.Last().To
               };

您可以调整日期时间比较以适合您的实际需求。在上面的linq查询中,我将每个组的最小From日期和最大To日期与匹配的期间日期进行比较。

这个比较:

(iGroup.Last().To - iGroup.First().From).Days + 1 == 
                            iGroup.Sum(g => (g.To - g.From).Days + 1)

检查日期范围内没有间隙的组。

修改

如果源数据存储在DataTable中,例如:

 DataTable items = new DataTable();
 items.Columns.Add("ID", typeof(string));
 items.Columns.Add("Name", typeof(string));
 items.Columns.Add("From", typeof(DateTime));
 items.Columns.Add("To", typeof(DateTime));

然后linq查询变得有点复杂:

var q = from i in items.AsEnumerable()
        orderby i.Field<DateTime>("From")
        group i by new { ID = i.Field<string>("ID"), Name = i.Field<string>("Name") } into iGroup
        where iGroup.First().Field<DateTime>("From") <= DateTime.Parse("2015/05/15") &&
              iGroup.Last().Field<DateTime>("To") >= DateTime.Parse("2015/07/1") &&
              (iGroup.Last().Field<DateTime>("To") - iGroup.First().Field<DateTime>("From")).Days + 1 ==
              iGroup.Sum(g => (g.Field<DateTime>("To") - g.Field<DateTime>("From")).Days + 1)
        select new
        {
            ID = iGroup.Key.ID,
            Name = iGroup.Key.Name,
            From = iGroup.First().Field<DateTime>("From"),
            To = iGroup.Last().Field<DateTime>("To")
        };

上述查询返回匿名类型的IEnumerable。可以使用Reflection将其转换回DataTable(例如,请参阅this帖子)。