4

F# でクエリ式を使用する方法を学ぶことに決め、Microsoft の公式ドキュメントを見つけました。警告は詳しく説明されていないようなので、簡単な修正で問題が発生したことは確かですが、表示されるエラーが表示される理由はわかりません。

私の考えは、結合とグループ化の両方を同時に実行するクエリを作成することでした。たとえば、サンプルの '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

私の推測では、エラーを解決したり、解決策を導き出すのに十分なほど、内部で何が起こっているのかを本当に理解していないということです。ここで私が欲しいものを照会することは可能ですか? 回避策はありますか?

4

3 に答える 3

1

ローカルで実行しようとすると、この例外が発生しました

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)
于 2017-07-26T14:28:31.463 に答える
0

同様の質問から回答を見つけました:

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)
于 2017-07-26T14:34:41.173 に答える