简体   繁体   中英

Translating GROUP BY / MIN DATE from SQL to LINQ

I have troubles with translating my SQL to LINQ, in order to work with the result as expecting...

Consider following table:

pkIdentifier  fkProject    fkFirst     fkSecond    Date
1             1030         1           1           03.08.2020 10:05:00
2             1030         1           2           03.08.2020 10:11:00
3             1030         3           1           03.08.2020 14:00:00
4             1030         3           2           03.08.2020 14:02:00
5             1040         1           1           03.08.2020 15:00:00
6             1050         2           1           04.08.2020 08:00:00
7             1050         2           2           04.08.2020 08:10:00
8             1050         2           3           04.08.2020 08:15:00

What I need here is to find the Projects, with the greatest "fkSecond" - and if there are more entries, then the one with the youngest Date.

That means, the result for the above table would be:

pkIdentifier  fkProject    fkFirst     fkSecond    Date
2             1030         1           2           03.08.2020 10:11:00
5             1040         1           1           03.08.2020 15:00:00
8             1050         2           3           04.08.2020 08:15:00

With the SQL below, it's nearly the same result that I expect:

SELECT ps.fkProject, ps.fkFirst, ps.fkSecond, min(ps.Date) as Date
FROM ProjectsStatus ps
    INNER JOIN (
        SELECT a.fkProject, MAX(a.fkSecond) as maxSecond
        FROM ProjectStatus a
        GROUP BY a.fkProject
    ) b ON ps.fkProject = b.fkProject and ps.fkSecond = b.maxSecond
group by ps.fkProject, ps.First, ps.Second

My attempt on LINQ, but missing the selection of only the entries with the youngest Date, if there are more entries with the same "fkSecond":

var query = this.dataContext.ProjectStatus.Where(
            x => x.fkSecond == this.dataContext.ProjectStatus.Where(y => y.fkProject == x.fkProject).Max(s => s.fkSecond)
          );

I'm currently also getting the second row with fkSecond=2 for Project 1030, but that's not what I want. I only want the one with the youngest Date, with is pkIdentifier 2.

pkIdentifier  fkProject    fkFirst     fkSecond    Date
2             1030         1           2           03.08.2020 10:11:00
4             1030         3           2           03.08.2020 14:02:00
5             1040         1           1           03.08.2020 15:00:00
8             1050         2           3           04.08.2020 08:15:00

See following:

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

namespace ConsoleApplication163
{
    class Program
    {
        static void Main(string[] args)
        {
            DataTable dt = new DataTable();

            dt.Columns.Add("pkIdentifier", typeof(int));
            dt.Columns.Add("fkProject", typeof(int));
            dt.Columns.Add("fkFirst", typeof(int));
            dt.Columns.Add("fkSecond", typeof(int));
            dt.Columns.Add("Date", typeof(DateTime));
            
            dt.Rows.Add(new object[] { 1, 1030, 1, 1, new DateTime(2020, 3, 8, 10, 5, 0)});
            dt.Rows.Add(new object[] { 2, 1030, 1, 2, new DateTime(2020, 3, 8, 10, 11, 0)});
            dt.Rows.Add(new object[] { 3, 1030, 3, 1, new DateTime(2020, 3, 8, 14, 0, 0)});
            dt.Rows.Add(new object[] { 4, 1030, 3, 2, new DateTime(2020, 3, 8, 14, 2, 0)});
            dt.Rows.Add(new object[] { 5, 1040, 1, 1, new DateTime(2020, 3, 8, 15, 0, 0)});
            dt.Rows.Add(new object[] { 6, 1050, 2, 1, new DateTime(2020, 3, 8, 8, 0, 0)});
            dt.Rows.Add(new object[] { 7, 1050, 2, 2, new DateTime(2020, 3, 8, 8, 10, 0)});
            dt.Rows.Add(new object[] { 8, 1050, 2, 3, new DateTime(2020, 3, 8, 8, 15, 0)});

            DataTable dt2 = dt.AsEnumerable()
                .OrderBy(x=> x.Field<int>("fkProject"))
                .ThenByDescending (x => x.Field<int>("fkSecond"))
                .ThenBy(x => x.Field<DateTime>("Date"))
                .GroupBy(x => x.Field<int>("fkProject"))
                .Select(x => x.First())
                .CopyToDataTable();

        }
    }
}

You can use a GroupBy as the following example will show:

class Data
{
    public int pkIdentifier { get; set; }
    public int fkProject { get; set; }
    public int fkFirst { get; set; }
    public int fkSecond { get; set; }
    public DateTime date { get; set; }
}

List<Data> dataList = new List<Data>();

dataList.Add(new Data { pkIdentifier = 1, fkProject = 1030, fkFirst = 1, fkSecond = 1, date = new DateTime(2020, 08, 03, 10, 05, 00) });
dataList.Add(new Data { pkIdentifier = 2, fkProject = 1030, fkFirst = 1, fkSecond = 2, date = new DateTime(2020, 08, 03, 10, 11, 00) });
dataList.Add(new Data { pkIdentifier = 3, fkProject = 1030, fkFirst = 3, fkSecond = 1, date = new DateTime(2020, 08, 03, 14, 00, 00) });
dataList.Add(new Data { pkIdentifier = 4, fkProject = 1030, fkFirst = 3, fkSecond = 2, date = new DateTime(2020, 08, 03, 14, 02, 00) });
dataList.Add(new Data { pkIdentifier = 5, fkProject = 1040, fkFirst = 1, fkSecond = 1, date = new DateTime(2020, 08, 03, 15, 00, 00) });
dataList.Add(new Data { pkIdentifier = 6, fkProject = 1050, fkFirst = 2, fkSecond = 1, date = new DateTime(2020, 08, 04, 08, 00, 00) });
dataList.Add(new Data { pkIdentifier = 7, fkProject = 1050, fkFirst = 2, fkSecond = 2, date = new DateTime(2020, 08, 04, 08, 10, 00) });
dataList.Add(new Data { pkIdentifier = 8, fkProject = 1050, fkFirst = 2, fkSecond = 3, date = new DateTime(2020, 08, 04, 08, 15, 00) });

var groupProject = dataList.GroupBy(i => i.fkProject).Select(groupItem => groupItem.OrderByDescending(dataItem => dataItem.fkSecond).ThenBy(dataItem => dataItem.date).First());

The GroupBy will group by project number and then order by fkSecond and then by date descending. Then taking the first element in each group.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM