加入/组/聚合的F#查询?

Joh*_*man 2 f# f#-3.0

我怎样才能让F#做到相当于

select a.id, avg(case when a.score = b.score then 1.0 else 0.0 end)
from table1 a join table2 b on a.id = b.id and a.date = b.date
group by a.id
Run Code Online (Sandbox Code Playgroud)

在查询表达式?我想出来了

query {
    for a in db.table1 do
    join b in db.table2 on ((a.id, a.date) = (b.id, b.date))
    groupBy a.id into g
    select (g.Key, ???) }
Run Code Online (Sandbox Code Playgroud)

但我无法弄清楚要插入"???"的内容.更糟糕的是,"得分"列可以为空,这使数学变得复杂.

或者,是否有更简单的方法来做到这一点?我对.NET数据库访问不是很熟悉.理想情况下,我只是给它一块SQL,它会解析它,并吐出一些类型的数据.实际上,试图找出简单SQL的非SQL语法非常令人沮丧.

Tom*_*cek 5

对于C#样式的LINQ操作,SQL的转换通常可以比使用本机F#函数更好地处理.所以它更容易去SelectAverage扩展方法比用像标准的F#的功能Seq.mapSeq.average.

我尝试使用示例Northwind数据库编写类似的分组 - 我没有找到很好的表来加入,但以下做基本聚合CASE并且工作正常:

open System.Linq

query {
    for p in db.Products do
    groupBy p.CategoryID.Value into g
    select (g.Key, g.Select(fun a -> 
      if a.UnitPrice.Value > 10.0M then 1.0 else 0.0).Average()) }
|> Array.ofSeq
Run Code Online (Sandbox Code Playgroud)

它生成的查询有点复杂,但看起来正确(并CASE在SQL端使用).你可以通过设置看到db.DataContext.Log <- System.Console.Out.

通常应该工作的另一件事是使用嵌套查询,但我没有尝试过.

  • 我可以确认嵌套查询也可以正常工作.select(g.Key,query {for a g do averageBy(如果a.UnitPrice.Value> 10.0M然后1.0其他0.0)}) (2认同)