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+SqlQueryable
1[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
извлечь наименьшее число.