Search code examples
linqrow-numberpartition

Multiple Row_number in LINQ


I tried to translate

select * 
from (
  select *, rng = row_number() over (partition by grp order by id)
  from (
    select *, grp = row_number() over (order by id) - row_number() over (partition by Name, Status, DateFinished order by id)
    from tooling ) g
  ) gn
where rng = 1
order by id

from an earlier question (Grouping with partition and over in TSql)

With help with Row_number over (Partition by xxx) in Linq? I got the solution to translate ONE of the row_number s but seems I'am out of luck to succesfully translate the entire question?
My attempt:

Tooling.OrderBy( x => x.Id)
    .GroupBy( x => new {x.Name,x.Status,x.DateFinished} )
    .Select( group => new { Group = group, Count = group.Count() } )
    .SelectMany( groupWithCount =>
        groupWithCount.Group.Select( b => b)
        .Zip(
            Enumerable.Range( 1, groupWithCount.Count ),
            ( j, i ) => new { j.Name,j.Status, j.DateFinished, RowNumber = i }
        )
    )

Solution

  • Try to use another way to get the result with LINQ. Get the previous record with ID < the current Id and check if all fields the same:

      var Res = Tooling.Where(x=>{ var r = Tooling.Where(y=>y.Id<x.Id).OrderByDescending(y=>y.Id).FirstOrDefault();
                                         if (r==null) return true;
                                         return !((r.Name==x.Name) && (r.Status==x.Status) && (r.DateFinished==x.DateFinished));
                                        })
                             .OrderBy( x => x.Id)
                             .Select(x=>x);
    

    UPD: Here is a test routine:

    public class TollingRecord
    {
    
        public int Id;
        public String Name;
        public int Status;
        public DateTime? DateFinished;
    
    }
    

    ...

    private static void TestT1()
            {
                TollingRecord[] Tooling = new TollingRecord[]{ new TollingRecord() {Id=1, Name="Large", Status=0, DateFinished=null },
                                new TollingRecord()  {Id=2, Name="Large", Status=1, DateFinished=null},
                                new TollingRecord()  {Id=3, Name="Small", Status=0, DateFinished=null},
                                new TollingRecord()  {Id=4, Name="Large", Status=2, DateFinished=null},
                                new TollingRecord()  {Id=5, Name="Large", Status=2, DateFinished=null},
                                new TollingRecord()  {Id=6, Name="Large", Status=1, DateFinished=null},
                                new TollingRecord()  {Id=7, Name="Large", Status=1, DateFinished=null},
                                new TollingRecord()  {Id=8, Name="Small", Status=1, DateFinished=DateTime.Now},
                              };
    
    
    
                var Res = Tooling.Where(x=>{ var r = Tooling.Where(y=>y.Id<x.Id).OrderByDescending(y=>y.Id).FirstOrDefault();
                                             if (r==null) return true;
                                             return !((r.Name==x.Name) && (r.Status==x.Status) && (r.DateFinished==x.DateFinished));
                                            })
                                 .OrderBy( x => x.Id)
                                 .Select(x=>x);
    
    
                foreach (var a in Res)
                {
                    Console.WriteLine("{0}/{1}/{2}", a.Id,a.Name,a.Status);
                }
    
            }
    

    Outputs:

    1/Large/0
    2/Large/1
    3/Small/0
    4/Large/2
    6/Large/1
    8/Small/1