在同一查询中使用联接和分组的 F# 查询表达式
F# Query Expression using join & groupBy in same query
我决定学习如何在 F# 中使用查询表达式并找到 the official Microsoft documentation。注意事项似乎没有详细说明,所以我确定我通过简单的修复遇到了问题,但不知道为什么我会收到它显示的错误。
我的想法是编写一个同时进行连接和分组的查询。例如,使用他们的示例 'MyDatabase' 我想我会尝试找到每个学生注册的 类 的数量。编写以下查询后,编译器没有标记警告,但是当我去运行 它给出了一个错误。
我的查询表达式:
query {
for student in db.Student do
join course in db.CourseSelection
on (student.StudentID = course.StudentID)
groupBy student into group
select (group.Key, group.Count())
}
|> Seq.iter (fun (student, classCount) -> printfn "Student %s has %i classes" student.Name classCount)
错误:
System.InvalidOperationException: Could not format node 'New' for execution as SQL.
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitNew(SqlNew sox)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
> at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitAlias(SqlAlias alias)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitSelect(SqlSelect ss)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitScalarSubSelect(SqlSubSelect ss)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitRow(SqlRow row)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitSelect(SqlSelect ss)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.Format(SqlNode node, Boolean isDebug)
at System.Data.Linq.SqlClient.SqlFormatter.Format(SqlNode node)
at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(ResultShape resultShape, Type resultType, SqlNode node, ReadOnlyCollection`1 parentParameters, SqlNodeAnnotations annotations)
at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations)
at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
at System.Data.Linq.DataQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc`2 action, IEnumerable`1 source)
at <StartupCode$FSI_0008>.$FSI_0008.main@() in C:\Users\JDKS\Library\query expressions.fsx:line 129
Stopped due to error
我什至认为我可以通过使用子查询来解决这个问题:
query {
for student in db.Student do
join course in db.CourseSelection
on (student.StudentID = course.StudentID)
let count = query {
for s in student.Name do
select course.CourseID
count
}
select (student.Name, count)
}
|> Seq.iter (fun (student, classCount) -> printfn "Student %s has %i classes" student classCount)
但这给出了更大的错误:
> System.NotSupportedException: Sequence operators not supported for type 'System.String'.
at System.Data.Linq.SqlClient.SqlBinder.Visitor.ConvertToFetchedSequence(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSequence(SqlSelect sel)
at System.Data.Linq.SqlClient.SqlVisitor.VisitScalarSubSelect(SqlSubSelect ss)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSubSelect(SqlSubSelect ss)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitExpression(SqlExpression expr)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.FetchExpression(SqlExpression expr)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitNew(SqlNew sox)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitExpression(SqlExpression expr)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitIncludeScope(SqlIncludeScope scope)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Bind(SqlNode node)
at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(ResultShape resultShape, Type resultType, SqlNode node, ReadOnlyCollection`1 parentParameters, SqlNodeAnnotations annotations)
at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations)
at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
at System.Data.Linq.DataQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc`2 action, IEnumerable`1 source)
at <StartupCode$FSI_0015>.$FSI_0015.main@() in C:\Users\JDKS\Library\query expressions.fsx:line 144
Stopped due to error
我的猜测是,我并不真正了解引擎盖下发生的事情,不足以找出错误或引导自己找到解决方案。可以在这里查询我想要的东西吗?有解决方法吗?
我认为您的第一个查询不起作用的原因是 groupBy student into group
。
我觉得你其实想写的是groupBy student.StudentID into group
.
当我在本地尝试 运行 时,我遇到了这个异常
System.Exception: Grouping over multiple tables is not supported yet
我不确定为什么您会收到该错误的不太漂亮的版本。但是,如果您将 GroupBy 从查询中拉出,一切似乎都很好。
query {
for student in db.Student do
join course in db.CourseSelection
on (student.StudentID = course.StudentID)
select (student.Name, course.Id)
}
|> Seq.countBy snd
|> Seq.iter (fun (student, classCount) -> printfn "Student %s has %i classes" student classCount)
我从 similar question:
找到了答案
query {
for student in db.Student do
join course in db.CourseSelection
on (student.StudentID = course.StudentID)
let count = query {
for c in db.CourseSelection do
where (c.StudentID = student.StudentID)
select c
count
}
select (student.Name, count)
distinct
}
|> Seq.iter (fun (student, classCount) -> printfn "Student %s has %i classes" student classCount)
这些查询表达式的基本范式仍然让我困惑。
编辑:
我发现您可以隐式连接而无需使用 join
运算符
query {
for student in db.Student do
let count = query {
for course in student.CourseSelection do
count
}
select (student.Name, count)
}
|> Seq.iter (fun (name, count) -> printfn "%s has %i courses" name count)
我决定学习如何在 F# 中使用查询表达式并找到 the official Microsoft documentation。注意事项似乎没有详细说明,所以我确定我通过简单的修复遇到了问题,但不知道为什么我会收到它显示的错误。
我的想法是编写一个同时进行连接和分组的查询。例如,使用他们的示例 'MyDatabase' 我想我会尝试找到每个学生注册的 类 的数量。编写以下查询后,编译器没有标记警告,但是当我去运行 它给出了一个错误。
我的查询表达式:
query {
for student in db.Student do
join course in db.CourseSelection
on (student.StudentID = course.StudentID)
groupBy student into group
select (group.Key, group.Count())
}
|> Seq.iter (fun (student, classCount) -> printfn "Student %s has %i classes" student.Name classCount)
错误:
System.InvalidOperationException: Could not format node 'New' for execution as SQL.
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitNew(SqlNew sox)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
> at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitAlias(SqlAlias alias)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitSelect(SqlSelect ss)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitScalarSubSelect(SqlSubSelect ss)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitRow(SqlRow row)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitSelect(SqlSelect ss)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.Format(SqlNode node, Boolean isDebug)
at System.Data.Linq.SqlClient.SqlFormatter.Format(SqlNode node)
at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(ResultShape resultShape, Type resultType, SqlNode node, ReadOnlyCollection`1 parentParameters, SqlNodeAnnotations annotations)
at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations)
at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
at System.Data.Linq.DataQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc`2 action, IEnumerable`1 source)
at <StartupCode$FSI_0008>.$FSI_0008.main@() in C:\Users\JDKS\Library\query expressions.fsx:line 129
Stopped due to error
我什至认为我可以通过使用子查询来解决这个问题:
query {
for student in db.Student do
join course in db.CourseSelection
on (student.StudentID = course.StudentID)
let count = query {
for s in student.Name do
select course.CourseID
count
}
select (student.Name, count)
}
|> Seq.iter (fun (student, classCount) -> printfn "Student %s has %i classes" student classCount)
但这给出了更大的错误:
> System.NotSupportedException: Sequence operators not supported for type 'System.String'.
at System.Data.Linq.SqlClient.SqlBinder.Visitor.ConvertToFetchedSequence(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSequence(SqlSelect sel)
at System.Data.Linq.SqlClient.SqlVisitor.VisitScalarSubSelect(SqlSubSelect ss)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSubSelect(SqlSubSelect ss)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitExpression(SqlExpression expr)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.FetchExpression(SqlExpression expr)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitNew(SqlNew sox)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitExpression(SqlExpression expr)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitIncludeScope(SqlIncludeScope scope)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Bind(SqlNode node)
at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(ResultShape resultShape, Type resultType, SqlNode node, ReadOnlyCollection`1 parentParameters, SqlNodeAnnotations annotations)
at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations)
at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
at System.Data.Linq.DataQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc`2 action, IEnumerable`1 source)
at <StartupCode$FSI_0015>.$FSI_0015.main@() in C:\Users\JDKS\Library\query expressions.fsx:line 144
Stopped due to error
我的猜测是,我并不真正了解引擎盖下发生的事情,不足以找出错误或引导自己找到解决方案。可以在这里查询我想要的东西吗?有解决方法吗?
我认为您的第一个查询不起作用的原因是 groupBy student into group
。
我觉得你其实想写的是groupBy student.StudentID into group
.
当我在本地尝试 运行 时,我遇到了这个异常
System.Exception: Grouping over multiple tables is not supported yet
我不确定为什么您会收到该错误的不太漂亮的版本。但是,如果您将 GroupBy 从查询中拉出,一切似乎都很好。
query {
for student in db.Student do
join course in db.CourseSelection
on (student.StudentID = course.StudentID)
select (student.Name, course.Id)
}
|> Seq.countBy snd
|> Seq.iter (fun (student, classCount) -> printfn "Student %s has %i classes" student classCount)
我从 similar question:
找到了答案query {
for student in db.Student do
join course in db.CourseSelection
on (student.StudentID = course.StudentID)
let count = query {
for c in db.CourseSelection do
where (c.StudentID = student.StudentID)
select c
count
}
select (student.Name, count)
distinct
}
|> Seq.iter (fun (student, classCount) -> printfn "Student %s has %i classes" student classCount)
这些查询表达式的基本范式仍然让我困惑。
编辑:
我发现您可以隐式连接而无需使用 join
运算符
query {
for student in db.Student do
let count = query {
for course in student.CourseSelection do
count
}
select (student.Name, count)
}
|> Seq.iter (fun (name, count) -> printfn "%s has %i courses" name count)