C# Linq查询:在max(日期)时选择ID的内容

C# Linq查询:在max(日期)时选择ID的内容,c#,sql,linq,C#,Sql,Linq,大家新年快乐!:-) 我已经搜索了几个小时,但我不知道如何使用Linq正确地构建查询 我有两张桌子:A和B 在表A中:我有A\u ID、B\u ID、VALUE\u DATE 在表B中:我有B_ID,状态 例如: A_ID=547值日期=01/05/10B_ID=14750 A_ID=547值日期=01/10/10B_ID=14750 我想使用B_ID加入A和B,其中VALUE_DATE为max。 目前,我所拥有的是: 上下文是OracleDataContextCommon对象 evalId和l

大家新年快乐!:-)

我已经搜索了几个小时,但我不知道如何使用Linq正确地构建查询

我有两张桌子:A和B

在表A中:我有A\u ID、B\u ID、VALUE\u DATE

在表B中:我有B_ID,状态

例如:

A_ID=547值日期=01/05/10B_ID=14750

A_ID=547值日期=01/10/10B_ID=14750

我想使用B_ID加入A和B,其中VALUE_DATE为max。 目前,我所拥有的是:

上下文是OracleDataContextCommon对象 evalId和listAffId是我的webservice方法的参数

var query = (from tabA in (from a in context.A
                          where listAffId.Contains(a.A_ID)
                          group a by a.A_IDinto grp
                          select new
                          {
                              pId = (int)grp.Key,
                              valDate = grp.Max(x => x.ValueDate),
                              bId = grp.Select(x => B_ID).FirstOrDefault()
                          })
                         join tabB in context.B on tabA.bIdequals equals tabB.B_ID
                         select new
                         {
                             affId = tabA.pId,
                             status = tabB.Status
                         });

我错在哪里?感谢您调查…

问题是您选择的是组的最大日期,但您选择的是组中的
FirstOrDefault
B_ID,它不一定和具有最大日期的行相关。最简单的方法可能是在分组之前按日期降序排列数据,然后在每组中为日期和
b_id
取第一项

注意,我已经用下面的一些虚拟数据切换了您的上下文

var theAs = new[]
{
   new {A_ID = 547, ValueDate = new DateTime(2010, 05, 01), B_ID = 14750}, 
   new {A_ID = 547, ValueDate = new DateTime(2010, 10, 01), B_ID = 14751}
};
var theBs = new[]
{
  new {B_ID = 14750, Status = "Foo"}, 
  new {B_ID = 14751, Status = "Bar"}
};
var listAffId = new[]{547};

var query = (from tabA in (from a in theAs
             where listAffId.Contains(a.A_ID)
             // Order the data - the first row per group is thus max date
             orderby a.ValueDate descending
             group a by a.A_ID into grp
             select new
             {
                 pId = (int)grp.Key,
                 // Now pull the date and B_ID from the same row
                 valDate = grp.First().ValueDate,
                 bId = grp.First().B_ID
             })
             join tabB in theBs on tabA.bId equals tabB.B_ID
             select new
             {
                 affId = tabA.pId,
                 status = tabB.Status
             });

我用类模拟代码。我认为这应该行得通

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Context context = new Context();
            List<int> listAffId = new List<int>() { 547 };

            var query = (from a in context.A where listAffId.Contains(a.A_ID)
                         join b in context.B on a.B_ID equals b.B_ID
                         select new { a = a, b = b})
                         .GroupBy(x => x.a.A_ID)
                         .Select(x => new { x = x, max = x.Max(y => y.a.VALUE_DATE)})
                         .Select(x => new {
                             affId = x.x.Key,
                             status = x.x.Where(y => y.a.VALUE_DATE == x.max).Select(y => y.b.STATUS).FirstOrDefault()
                         }).ToList();



        }
    }
    public class Context
    {
        public List<TableA> A { get; set; }
        public List<TableB> B { get; set; }
    }
    public class TableA
    {
        public int A_ID { get; set; }
        public int B_ID { get; set; }
        public DateTime VALUE_DATE { get; set; }
    }
    public class TableB
    {
        public int B_ID { get; set; }
        public string STATUS { get; set; }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
命名空间控制台应用程序1
{
班级计划
{
静态void Main(字符串[]参数)
{
上下文=新上下文();
List listAffId=new List(){547};
var query=(来自context.a,其中listAffId.Contains(a.a_ID)
在上下文中加入b。a.b_ID上的b等于b.b_ID
选择新的{a=a,b=b})
.GroupBy(x=>x.a.a_ID)
.Select(x=>new{x=x,max=x.max(y=>y.a.VALUE\u DATE)})
.选择(x=>new{
粘贴=x.x.键,
status=x.x.Where(y=>y.a.VALUE\u DATE==x.max)。选择(y=>y.b.status)。FirstOrDefault()
}).ToList();
}
}
公共类上下文
{
公共列表A{get;set;}
公共列表B{get;set;}
}
公共类表格
{
公共int A_ID{get;set;}
公共int B_ID{get;set;}
公共日期时间值_DATE{get;set;}
}
公共类表格B
{
公共int B_ID{get;set;}
公共字符串状态{get;set;}
}
}

您需要选择最大日期的
B_ID
,因此首先查找最大日期:

var query = (from tabA in (from a in context.A
                          where listAffId.Contains(a.A_ID)
                          group a by a.A_IDinto grp
                          let maxdate = grp.Max(a => a.ValueDate)
                          select new
                          {
                              pId = (int)grp.Key,
                              valDate = maxdate,
                              bId = grp.Where(a => a.ValueDate == maxdate).Select(x => B_ID).FirstOrDefault()
                          })
                         join tabB in context.B on tabA.bId equals equals tabB.B_ID
                         select new
                         {
                             affId = tabA.pId,
                             status = tabB.Status
                         });

这是我考虑过的,我不熟悉Linq,我想去掉FirstOrDefault,但是如果我不使用这种单行选择器,推理类型在连接时失败…:-/。非常感谢您的解决方案,这听起来像是一个解决方案(因为我不想对结果进行排序),但它可以保存:-)。我比你高!我忽略了关于“让”的声明,这是伟大的人,谢谢!我试图使用grp.Where(…),但无法想出下一步。你做得很容易…:-)我接受了你的答案,并且投票给了你
let
不是我最喜欢的(它通常是通过对一个新的临时对象执行
select
来实现的(如果你想在lambda中执行),但我想SQL translation可以处理非对象的情况),但是当需要干的或分解我们昂贵的操作时,它非常有用(请参阅)谢谢你的工作人员,看起来像上面的答案,我想避免排序步骤(表中有很多记录)。我比你高!:-)我修改了代码以消除完整排序并使用max。我的代码使用一个from而不是两个嵌套from要简单得多。执行时间从N*N/2(排序)到(3/2)N(在整个列表中搜索一次max,然后找到max)的确,很好的一个!)排序应该是O(N*logn),不要认为这里会有冒泡排序!我不确定下面的代码是否执行了N次,或者优化器将删除冗余:x.Max(z=>z.a.VALUE\u DATE)。我可以移动代码,使其只编译一次。