F# sqlite sqlprovider minBy maxBy с использованием float

У меня есть таблица sqlite с сочетанием целочисленных и плавающих столбцов. Я пытаюсь получить максимальные и минимальные значения каждого столбца. Для целочисленных столбцов работает следующий код, но я получаю ошибку приведения при использовании того же кода для столбцов с плавающей точкой:

let numCats = query{for row in db do minBy row.NumCats}

Для плавающих столбцов я использую следующий код, но он медленный.

let CatHight = query{for row in db do select row.CatHeight} |> Seq.toArray |> Array.max

У меня есть 8 целочисленных столбцов и 9 столбцов с плавающей запятой, и поведение было одинаковым для всех столбцов, поэтому я думаю, что это проблема с типом столбца. Но я новичок в F# и ничего не знаю, поэтому надеюсь, что вы мне поможете.

Спасибо, что нашли время помочь, это очень ценится.

Версия SQLProvider: 1.0.41

System.Data.SQLite.Core версия: 1.0.104

Ошибка: System.InvalidCastException произошла в FSharp.Core.dll

Добавленная информация

Я создал новую таблицу с одним столбцом типа float. Я вставил значения 2.2 и 4.2. Используя SQLProvider и System.Data.SQLite.Core, я подключился к базе данных, используя minBy или maxBy, и получил исключение приведения. Если тип столбца целочисленный, он работает правильно.

Дополнительная информация

Деталь исключения:

System.Exception было необработанным. Сообщение: необработанное исключение типа 'System.Exception' произошло в>FSharp.Core.dll Дополнительная информация: неподдерживаемое выражение выполнения value(FSharp.Data.Sql.Runtime.QueryImplementation+SqlQueryable1[FSharp.>Data.Sql.Common.SqlEntity]).Min(row => >Convert(Convert(row.GetColumn("X"))))`

Код, который не работает:

open FSharp.Data.Sql

[<Literal>]
let ConnectionString =
"Data Source=c:\MyDB.db;" +
"Version=3;foreign keys=true"

type Sql = SqlDataProvider<Common.DatabaseProviderTypes.SQLITE,
ConnectionString,
//ResolutionPath = resolutionPath,
CaseSensitivityChange = Common.CaseSensitivityChange.ORIGINAL>

let ctx = Sql.GetDataContext()
let Db = ctx.Main.Test

let x = query{for row in Db do minBy row.X}
printfn "x: %A" x

Обновление 1/1/17

Другой пользователь смог воспроизвести проблему, поэтому я подал проблему в SQLProvider. Сейчас я смотрю на обходные пути, и хотя следующий код работает и работает быстро, я знаю, что есть лучший способ сделать это - я просто не могу найти правильный путь. Если кто-то ответит с лучшим кодом, я приму этот ответ. Еще раз спасибо всем за помощь.

let x = query {for row in db do
                sortBy row.Column
                take 1
                select row.Column } |> Seq.toArray |> Array.min

2 ответа

Решение

Это мой обходной путь, с которым @s952163 и хорошие люди в чате SO F# помогли мне. Еще раз спасибо всем, кто помог.

let x = query {for row in db do
                sortBy row.Column
                take 1
                select row.Column } |> Seq.head

Вы должны заставить выходной столбец int или же float (в зависимости от того, что вам нужно или доставляет вам неприятности). Вы также должны позаботиться о том, чтобы какие-либо из ваших столбцов могли обнуляться. Пример ниже приведёт столбец к float сначала (чтобы позабыть обнуляемым), затем преобразовать его в intи, наконец, получить минимум:

let x = query { for row in MYTABLE do
                minBy (int (float row.MYCOLUMN))}

Вы можете изменить порядок, конечно, или просто сказать float Mycolumn,

Обновление: с Sqlite это действительно вызывает ошибку. Вы можете захотеть сделать query { ... } |> Seq.minBy извлечь наименьшее число.

Другие вопросы по тегам