3

I have this table in DB:

ID    | Timestamp           | Score
------|---------------------|-------------------
1     | 2013-01-01 12:00:00 | 15
1     | 2013-01-02 11:00:00 | 1
1     | 2013-01-03 16:00:00 | 4
2     | 2013-01-08 04:00:00 | 7
2     | 2013-01-09 08:00:00 | 9
2     | 2013-01-10 11:00:00 | 6
3     | 2013-01-03 12:00:00 | 14
3     | 2013-01-01 10:00:00 | 15
3     | 2013-01-02 00:00:00 | 17

What I need is a last Score for each ID. In other words, for each ID, I need to pick the row with highest Timestamp and then get the Score from that row.

I managed to do that in SQL server like this (which may not be optimal)

SELECT ID, Timestamp, Score FROM Data cd
LEFT OUTER JOIN
    (SELECT ID as SubId, MAX(Timestamp) AS TS 
     FROM Data GROUP BY ID) AS SUB
ON cd.ID = SUB.SubId
WHERE Timestamp = TS

I need a LINQ to Entities (v4) solution to this situation, but I am unsure how to approach subqueries and grouping in this situation.

@Edit (in reply to comments): I've tried something like the following, but I don't know how to get the Score from that grouped item, or how to integrate the subquery into this.

from d in Datas
group d by d.ID into group
select new { ID = group.Key, TS = group.Max(i => i.Timestamp) }

Is this scenario possible? Is there any better solution (performance-wise)?

Kornelije Petak
  • 9,412
  • 15
  • 68
  • 96

1 Answers1

0

This should achieve what you are wanting:

from d in Datas
group d by d.ID into g
let maxDate = g.Max(d => d.Timestamp) 
select new 
{
    ID = g.Key, 
    Score = g.First(item => item.Timestamp == maxDate).Score
};

Here's a copy of the complete code listing that I used in LINQPad:

void Main()
{
    var testData = GenerateTestData();

    var result = 
        from d in testData
        group d by d.ID into g
        let maxDate = g.Max(d => d.Timestamp) 
        select new 
        {
            ID = g.Key, 
            Score = g.First(item => item.Timestamp == maxDate).Score
        };

    foreach (var item in result)
    {
        Console.WriteLine("ID={0}; Score={1}", item.ID, item.Score);
    }
}

List<Item> GenerateTestData()
{
    List<Item> list = new List<Item>();
    list.Add(new Item(1, "2013-01-01 12:00:00", 15));
    list.Add(new Item(1, "2013-01-02 11:00:00", 1));
    list.Add(new Item(1, "2013-01-03 16:00:00", 4));
    list.Add(new Item(2, "2013-01-08 04:00:00", 7));
    list.Add(new Item(2, "2013-01-09 08:00:00", 9));
    list.Add(new Item(2, "2013-01-10 11:00:00", 6));
    list.Add(new Item(3, "2013-01-03 12:00:00", 14));
    list.Add(new Item(3, "2013-01-01 10:00:00", 15));
    list.Add(new Item(3, "2013-01-02 00:00:00", 17));
    return list;
}

class Item
{
    public Item(int id, string timestamp, int score)
    {
        ID = id;
        Timestamp = DateTime.Parse(timestamp);
        Score = score;
    }
    public int ID;
    public DateTime Timestamp;
    public int Score;
}

Which produced the output:

ID=1; Score=4
ID=2; Score=6
ID=3; Score=14
Ɖiamond ǤeezeƦ
  • 3,223
  • 3
  • 28
  • 40