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

时间:2014-04-17 12:22:31

标签: 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

在查询表达式中?我提出了

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, ???) }

但是我无法弄清楚要插入" ???"。更糟糕的是,"得分" column可以为null,这会使数学变得复杂。

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

2 个答案:

答案 0 :(得分:5)

对SQL的转换通常可以更好地处理C#样式的LINQ操作,而不是使用本机F#函数。因此,使用SelectAverage扩展方法比使用Seq.mapSeq.average等标准F#函数更容易。

我尝试使用示例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

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

来查看

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

答案 1 :(得分:0)

现在好几年了,但从来没有太晚?这有什么帮助吗?特别要注意FirstOrDefault的使用。对不起挪威的名字,但这并不重要。 “x”表示访问第一个表。

type Result3 = { Aarsak: int; Beskrivelse: string; Antall: int; Varighet: Nullable<int> }
let query3 = query {
    for stopptid in dc.StoppTider do
    where (stopptid.DatoS = datoS && stopptid.SkiftNr = skiftNr)
    groupBy stopptid.Aarsak into g
    join stoppaarsak in dc.StoppAarsak on (g.FirstOrDefault().Aarsak.ToString() = stoppaarsak.Nr)
    select { Aarsak = g.Key; Beskrivelse = stoppaarsak.Norsk; Antall = g.Count(); Varighet = g.Sum(fun x -> x.Varighet) }
    }

谷歌搜索时我第一次来到这里。由于它没有帮助,我用C#搜索了相同的解决方案,得到了SO的打击,让它在C#中为我的情况工作,然后在F#中。这是链接:

LINQ: combining join and group by