2017-07-26 108 views
4

我決定學習如何在F#中使用查詢表達式並找到the official Microsoft documentation。警告似乎沒有拼寫出來,所以我敢肯定我遇到了一個簡單的修復問題,但不知道爲什麼我得到它顯示的錯誤。F#在同一查詢中使用join&groupBy查詢表達式

我的想法是編寫一個查詢,同時執行加入和分組。例如,使用他們的示例'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>[email protected]() 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>[email protected]() in C:\Users\JDKS\Library\query expressions.fsx:line 144 
Stopped due to error 

我的猜測是,我並不真正瞭解發動機罩下發生了什麼事情,足以解決這個錯誤或讓我自己找到解決方案。有沒有可能在這裏查詢我想要的內容?有沒有解決方法?

+0

我想這是因爲在查詢結束的元組。嘗試沒有它。 –

+0

我試過沒有元組,它沒有工作。然後,我先嚐試分組,然後加入併成功。但這不是我想要的。你只能'groupBy''student.StudentID',因爲這是加入到'CourseSelection'的列。我正努力想要說明這一點,但我不能相信沒有辦法將姓名分組並直接計算課程。 – jks612

+0

'for s in student.Name'正在嘗試迭代名稱中的字符,這就是爲什麼在第二個查詢中出現此錯誤 –

回答

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) 
+0

我認爲你的countBy應該是'fst'而不是'snd' – jks612

+0

這真的很奇怪,我的錯誤是如此之大。你運行的是F#版本14.0.23413.0嗎? – jks612

+0

但是這會在客戶端進行分組。巨大的性能損失。 –

0

我相信你的第一個查詢不工作的原因是因爲groupBy student into group

我想你實際上想寫的是groupBy student.StudentID into group

+0

剛剛嘗試過。它也給出了一個錯誤 – jks612

0

我發現從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)