2011-07-01 202 views
7

Tengo tres columnas en una datatable: cadena, DateTime y decimal. Quiero agrupar por la columna de cadena y decimal, y para las filas agrupadas quiero sumar los valores decimales. Sé cómo hacer la parte de suma, pero ¿cómo se agrupan dos columnas diferentes en una tabla de datos?C# usando linq para agrupar por varias columnas en una tabla de datos

Este es mi código hasta ahora que no funciona correctamente:

var newSort = from row in objectTable.AsEnumerable() 
       group row by new {ID = row.Field<string>("resource_name"), time1 = row.Field<DateTime>("day_date")} into grp 
       orderby grp.Key 
       select new 
       { 
       resource_name1 = grp.Key.ID, 
       day_date1 = grp.Key.time1, 
       Sum = grp.Sum(r => r.Field<Decimal>("actual_hrs")) 
       }; 
+1

"El compilador cree que todo el obj Los efectos son los mismos, por lo que cada fila se agrupa "- ¿Quiere decir que todos los objetos se ponen en un gran grupo, por lo que termina con un solo elemento en la colección' nuevaSort'? – StriplingWarrior

+0

sí, newSort solo contiene el último elemento de la tabla de datos – Sam

+0

La consulta me parece correcta. ¿Puedes verificar y volver a verificar tus entradas? – StriplingWarrior

Respuesta

14

No creo que nos está dando la historia completa. Aparte de orderby que no funciona con tipos anónimos (el código que proporcionó no se habría compilado), su consulta debería funcionar de la manera que desee. Acabo de poner esto en LINQPad:

var objectTable = new DataTable(); 
objectTable.Columns.Add("resource_name",typeof(string)); 
objectTable.Columns.Add("day_date",typeof(DateTime)); 
objectTable.Columns.Add("actual_hrs",typeof(decimal)); 
objectTable.Rows.Add(1, DateTime.Today, 1); 
objectTable.Rows.Add(2, DateTime.Today, 2); 

var newSort = from row in objectTable.AsEnumerable() 
      group row by new {ID = row.Field<string>("resource_name"), time1 = row.Field<DateTime>("day_date")} into grp 
      select new 
       { 
        resource_name1 = grp.Key.ID, 
        day_date1 = grp.Key.time1, 
        Sum = grp.Sum(r => r.Field<Decimal>("actual_hrs")) 
       }; 
newSort.Dump(); 

... y me dieron estos resultados:

resource_name1 | day_date1   | Sum 
1    | 7/1/2011 12:00:00 AM | 1 
2    | 7/1/2011 12:00:00 AM | 2 
+0

Es curioso saber cómo puedo extraer una fila de cada grupo de la anterior en función del valor MIN de otras dos columnas combinadas. – Si8

+0

@ Si8: 'grp.OrderBy (g => g.col1 + g.col2) .FirstOrDefault()'? – StriplingWarrior

3

uso este código

var newSort = from row in objectTable.AsEnumerable() 
      group row by new {ID = row.Field<string>("resource_name"), time1 = row.Field<DateTime>("day_date")} into grp 
      orderby grp.Key 
      select new 
      { 
      resource_name1 = grp.Key.ID, 
      day_date1 = grp.Key.time1, 
      Sum = grp.Sum(r => Convert.ToDecimal(r.ItemArray[2])) 
      }; 
0

para aquellos que quieren una solución en Vb.net , aquí hay un ejemplo:

Dim workTable As DataTable = New DataTable("Customers") 

Dim workCol As DataColumn = workTable.Columns.Add("ID", Type.GetType("System.Int32")) 
workTable.Columns.Add("Total", Type.GetType("System.Decimal")) 
workTable.Columns.Add("Compra", Type.GetType("System.Decimal")) 

Dim row As DataRow = workTable.NewRow() 
row("id") = 2 
row("total") = 1.5 
row("compra") = 3 
workTable.Rows.Add(row) 
row = workTable.NewRow() 

row("id") = 1 
row("total") = 1.5 
row("compra") = 3.3999999999999999 
workTable.Rows.Add(row) 
row = workTable.NewRow() 
row("id") = 1 
row("total") = 1.5 
row("compra") = 5 
workTable.Rows.Add(row) 


Dim detalles As IEnumerable(Of DataRow) = workTable.AsEnumerable() 

Dim query = From detalle In detalles.AsEnumerable() _ 
      Group detalle By grupoClave = New With _ 
             { _ 
              Key .C2 = detalle("id"), _ 
              Key .C4 = detalle("total")} Into g = Group _ 
            Select New With _ 
            { _ 
             .Col2 = g(0).Field(Of Integer)("id"), _ 
             .Col3 = g(0).Field(Of Decimal)("total"), _ 
             .Col4 = g.Sum(Function(fact) fact.Field(Of Decimal)("compra")) _ 
            } 

For Each p In query 
    Console.WriteLine((p.Col2 & p.Col3 & p.Col4)) 
Next 
Cuestiones relacionadas