F# 查询:查找每组中具有最大值的行
F# query: find rows with max value in each group
在我的项目中我使用:
- 带有查询工作流的 F#
- Entity Framework 核心 3.11
- MS SQL
我有一个与此类似的问题:SQL select only rows with max value on a column,但我想知道如何使用 F# 查询工作流表达该问题中出现的 SQL:
SELECT a.id, a.rev, a.contents
FROM YourTable a
INNER JOIN (
SELECT id, MAX(rev) rev
FROM YourTable
GROUP BY id
) b ON a.id = b.id AND a.rev = b.rev
直接翻译
对于直接翻译,内部查询是:
let innerQuery =
query {
for inner in ctx.YourTable do
groupBy inner.id into grp
select (grp.Key, grp.Max(fun ent -> ent.rev))
}
然后,理论上,我认为完整的查询应该是:
query {
for outer in ctx.YourTable do
join inner in innerQuery
on ((outer.id, outer.rev) = inner)
select outer
}
但是,这不起作用:
Type mismatch when building 'ty': function type doesn't match delegate type. Expected
'Microsoft.FSharp.Core.FSharpFunc`2[Program+YourTable,System.Tuple`2[System.Int32,System.Int32]]'
, but received type
'Microsoft.FSharp.Core.FSharpFunc`2[Program+YourTable,Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject`2[System.Int32,System.Int32]]'.
我可能是错的,也可能是 bug/limitation。也许有人有解决方法。
替代翻译
但是,如果您接受略有不同的翻译,它确实有效:
query {
for outer in ctx.YourTable do
where (
query {
for inner in ctx.YourTable do
groupBy inner.id into grp
exists (grp.Key = outer.id && grp.Max(fun ent -> ent.rev) = outer.rev)
})
select outer
}
生成的SQL为:
SELECT [y].[id], [y].[rev], [y].[contents]
FROM [YourTable] AS [y]
WHERE EXISTS (
SELECT 1
FROM [YourTable] AS [y0]
GROUP BY [y0].[id]
HAVING ([y0].[id] = [y].[id]) AND (MAX([y0].[rev]) = [y].[rev]))
输出为:
{ id = 2
rev = 1
contents = "..." }
{ id = 1
rev = 3
contents = "..." }
请注意,我在构建模型时必须设置 id, rev
的复合主键:
override __.OnModelCreating(modelBuilder: ModelBuilder) =
modelBuilder.Entity<YourTable>()
.HasKey([| "id"; "rev" |]) |> ignore
完整代码是 here.
在我的项目中我使用:
- 带有查询工作流的 F#
- Entity Framework 核心 3.11
- MS SQL
我有一个与此类似的问题:SQL select only rows with max value on a column,但我想知道如何使用 F# 查询工作流表达该问题中出现的 SQL:
SELECT a.id, a.rev, a.contents
FROM YourTable a
INNER JOIN (
SELECT id, MAX(rev) rev
FROM YourTable
GROUP BY id
) b ON a.id = b.id AND a.rev = b.rev
直接翻译
对于直接翻译,内部查询是:
let innerQuery =
query {
for inner in ctx.YourTable do
groupBy inner.id into grp
select (grp.Key, grp.Max(fun ent -> ent.rev))
}
然后,理论上,我认为完整的查询应该是:
query {
for outer in ctx.YourTable do
join inner in innerQuery
on ((outer.id, outer.rev) = inner)
select outer
}
但是,这不起作用:
Type mismatch when building 'ty': function type doesn't match delegate type. Expected
'Microsoft.FSharp.Core.FSharpFunc`2[Program+YourTable,System.Tuple`2[System.Int32,System.Int32]]'
, but received type
'Microsoft.FSharp.Core.FSharpFunc`2[Program+YourTable,Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject`2[System.Int32,System.Int32]]'.
我可能是错的,也可能是 bug/limitation。也许有人有解决方法。
替代翻译
但是,如果您接受略有不同的翻译,它确实有效:
query {
for outer in ctx.YourTable do
where (
query {
for inner in ctx.YourTable do
groupBy inner.id into grp
exists (grp.Key = outer.id && grp.Max(fun ent -> ent.rev) = outer.rev)
})
select outer
}
生成的SQL为:
SELECT [y].[id], [y].[rev], [y].[contents]
FROM [YourTable] AS [y]
WHERE EXISTS (
SELECT 1
FROM [YourTable] AS [y0]
GROUP BY [y0].[id]
HAVING ([y0].[id] = [y].[id]) AND (MAX([y0].[rev]) = [y].[rev]))
输出为:
{ id = 2
rev = 1
contents = "..." }
{ id = 1
rev = 3
contents = "..." }
请注意,我在构建模型时必须设置 id, rev
的复合主键:
override __.OnModelCreating(modelBuilder: ModelBuilder) =
modelBuilder.Entity<YourTable>()
.HasKey([| "id"; "rev" |]) |> ignore
完整代码是 here.