Just trying out F# 3.0 and hit a bit of a wall when it comes to grouping by multiple columns. The obvious thing to try was
query { for d in context.table do groupBy (d.col1,d.col2) into g select (g.Key) }
But I get a "Only parameterless constructors and initializers are supported in LINQ to Entities." exception.
I can't seem to find an example on msdn
http://msdn.microsoft.com/en-us/library/hh225374(v=vs.110).aspx
http://msdn.microsoft.com/en-us/library/hh361035(v=vs.110).aspx
And I realize my question is similar to " Entity Framework and Anonymous Types in F#" but it seems to be powerpack/F#2.x focused and I'm hoping F# 3.0 has an elegant answer... Any ideas?
UPDATE:
I came across the CLIMutable attribute from reading Brian's post at:
http://blogs.msdn.com/b/fsharpteam/archive/2012/07/19/more-about-fsharp-3.0-language-features.aspx
I was pretty optimistic so I tried
[<CLIMutable>] type MyRecord = { Column1 : int; Column2 : int } query { for d in context.table do groupBy {Column1 = col1; Column2 = col2} into g select (g.Key) }
Unfortunately I get the exact same exception.
How to groupby multiple columns in pandas DataFrame and compute multiple aggregations? groupby() can take the list of columns to group by multiple columns and use the aggregate functions to apply single or multiple aggregations at the same time.
Use DataFrame. groupby(). sum() to group rows based on one or multiple columns and calculate sum agg function. groupby() function returns a DataFrameGroupBy object which contains an aggregate function sum() to calculate a sum of a given column for each group.
Pandas comes with a whole host of sql-like aggregation functions you can apply when grouping on one or more columns. This is Python's closest equivalent to dplyr's group_by + summarise logic.
We can group the resultset in SQL on multiple column values. When we define the grouping criteria on more than one column, all the records having the same value for the columns defined in the group by clause are collectively represented using a single record in the query output.
The following is an example of multiple columns being used for grouping in c# and converted to f# (overly paranoid management has made me rename everything, but I believe I have been consistent):
(TheDatabase was generated by SqlMetal, GetSummedValuesResult is a F# record type)
c#
public static class Reports { public static IReadOnlyList<GetSummedValuesResult> GetSummedValues(TheDatabase db, DateTime startDate, DateTime? endDate) { var query = from sv in db.SomeValues where (sv.ADate >= startDate && sv.ADate <= (endDate ?? startDate)) group sv by new { sv.ADate, sv.Owner.Name } into grouping select new GetSummedValuesResult( grouping.Key.ADate, grouping.Key.Name, grouping.Sum(g => g.Value) ); return query.ToList(); } }
f#
type Reports() = static member GetSummedValues (db:TheDatabase) startDate (endDate:Nullable<DateTime>) = let endDate = if endDate.HasValue then endDate.Value else startDate let q = query { for sv in db.SomeValues do where (sv.ADate >= startDate && sv.ADate <= endDate) let key = AnonymousObject<_,_>(sv.ADate, sv.Owner.Name) groupValBy sv key into grouping select { ADate = grouping.Key.Item1; AName = grouping.Key.Item2; SummedValues = grouping.Sum (fun (g:TheDatabaseSchema.SomeValues) -> g.Value) } } List(q) :> IReadOnlyList<GetSummedValuesResult>
So the thing to use is Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject
Note that you should not use the Seq module for aggregation functions!!
SummedValues = grouping |> Seq.sumBy (fun g -> g.SomeValues)
Although this WILL WORK, it does the aggregation on the client side, rather than formulating appropriate SQL.
I see this in first of your links, I think it is what you want:
query { for student in db.Student do groupValBy student.Name student.Age into g select (g, g.Key, g.Count()) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With