Linq查询以选择列为最大值的行

时间:2016-09-14 17:13:10

标签: linq f#

我想查询一个类似下面简化示例的数据库表:

Quote  | Sequence  | Item
-------|-----------|-----
    1  |    1.0M   | a
    1  |    2.0M   | a
    1  |    3.0M   | a
    1  |    1.0M   | b
    1  |    2.0M   | b
    1  |    3.0M   | b
    2  |    1.0M   | x
    2  |    2.0M   | x
    3  |    1.0M   | y

我需要一个查询来获取给定Quote的所有行,其中Sequence是该列的最大值:

Quote  | Sequence  | Item
-------|-----------|-----
    1  |    3.0M   | a
    1  |    3.0M   | b
    2  |    2.0M   | x
    3  |    1.0M   | y

我正在使用F#System.Data.Linq

我可以用

let quoteQuery = 
    query{
        for row in db.[TABLE] do 
        select row
        }

获取所有行,但我不知道Linq已经足够 - 但是 - 修改它以获得将产生所需结果的查询。我尝试使用the answer from this question来尝试修改我的查询,但是我试图修改(猜测?)必要的语法/语言时遇到了障碍。

我可以找到几个SQL示例,但很少有Linq特定的。

2 个答案:

答案 0 :(得分:1)

正如评论中暗示的那样,这不是Linq,而是f#查询表达式。

事实上,这实际上不是这个问题的真正含义。

它更多的集合和关系代数。或者某事......

那说:这里的事情是,如果你分组然后获得每个组的最大元素,那么你很好。请注意,示例代码不能对任何数据库或其他方式起作用,但这应该很容易替换。

type Table = 
    {
        Quote:int
        Sequence: decimal
        Item: string
    }

let createTableEntry (q,s,i) = 
    {
        Quote = q
        Sequence = s
        Item = i
    }

let printTR {Quote=q;Sequence=s;Item=i} = printfn "%A   |  %A  | %A" q s i 

let table =
    [
        (1  ,    1.0M   , "a")
        (1  ,    2.0M   , "a")
        (1  ,    3.0M   , "a")
        (1  ,    1.0M   , "b")
        (1  ,    2.0M   , "b")
        (1  ,    3.0M   , "b")
        (2  ,    1.0M   , "x")
        (2  ,    2.0M   , "x")
        (3  ,    1.0M   , "y")
    ]
    |> List.map createTableEntry

let result = 
    table
    |> List.groupBy (fun x -> x.Quote, x.Item) //group "unique" by Quote&Item
    |> List.map (fun x -> snd x |> List.max)   //get max of each group, i.e. max of Sequence


result |> Seq.iter printTR

1   |  3.0M  | "a"
1   |  3.0M  | "b"
2   |  2.0M  | "x"
3   |  1.0M  | "y"

附录

在Ivan Stoev部分“错误地”回答之后。这是一个“更正”的版本,它与上面的版本“相同”(不完全相同,但是......):

let quoteQuery =
    query {
        for row in table do
        groupBy (row.Quote, row.Item) into g
        let maxRow =
            query {
                for row in g do
                sortBy row.Sequence
                headOrDefault
            }
        select maxRow
    }

quoteQuery |> Seq.iter printTR

附录II

由于我编辑并说Ivans的答案与第一个代码示例并不完全相同,我还添加了一个与查询表达式“完全相同”的答案:

let quoteQuery' =
    query {
        for row in table do
        groupBy (row.Quote, row.Item) into g
        let maxRow =
            query {
                for row in g do
                maxBy row.Sequence
            }
        select (fst g.Key, maxRow, snd g.Key)
    }|>Seq.map createTableEntry

quoteQuery' |> Seq.iter printTR

答案 1 :(得分:0)

F#查询表达式被称为查询表达式,因为它们遵循(丢失)LINQ查询语法(vs方法语法)并且它们实现了Linq.IQueriable。因此我也将它们视为LINQ。虽然它可能不是惯用的,但上述查询可以在方法语法中重写。如果你想念MoreLinq,那就非常棒了。从@HelgeReneUrholm“窃取”上表定义:

open MoreLinq

table
    .GroupBy(fun x -> (x.Quote,x.Item))
    .Select(fun x -> x.MaxBy(fun x -> x.Sequence)) |> Seq.iter printTR
  

1 | 3.0M | “一”
  1 | 3.0M | “B”
  2 | 2.0M | “X”
  3 | 1.0M | “y”