Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

groupby multiple columns in a F# 3.0 query

Tags:

f#

f#-3.0

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.

like image 237
Jizugu Avatar asked Dec 27 '11 23:12

Jizugu


People also ask

Can you Groupby multiple columns in pandas?

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.

How do I sum multiple columns in a group by?

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.

Can I group by 2 columns in Python?

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.

Can you group by multiple columns in SQL?

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.


2 Answers

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.

like image 125
Paul Westcott Avatar answered Sep 28 '22 05:09

Paul Westcott


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()) } 
like image 29
tomasK Avatar answered Sep 28 '22 04:09

tomasK