F# query expressions - restriction using string comparison in SqlProvider with SQLite - sqlite

SQLite doesn't really have date columns. You can store your dates as ISO-8601 strings, or as the integer number of seconds since the epoch, or as Julian day numbers. In the table I'm using, I want my dates to be human-readable, so I've chosen to use ISO-8601 strings.
Suppose I want to query all the records with dates after today. The ISO-8601 strings will sort properly, so I should be able to use string comparison with the ISO-8601 string for today's date.
However, I see no way to do the comparison using the F# SqlProvider type provider. I'm hoping that this is just a reflection of my lack of knowledge of F# query expressions.
For instance, I can't do:
query {
for calendarEntry in dataContext.``[main].[calendar_entries]`` do
where (calendarEntry.date >= System.DateTime.Today.ToString("yyyy-MM-dd hh:mm:ss"))
... }
I get:
The binary operator GreaterThanOrEqual is not defined for the types 'System.String' and 'System.String'.
I also can't do any variation of:
query {
for calendarEntry in dataContext.``[main].[calendar_entries]`` do
where (calendarEntry.date.CompareTo(System.DateTime.Today.ToString("yyyy-MM-dd hh:mm:ss")) >= 0)
... }
I get:
Unsupported expression. Ensure all server-side objects appear on the left hand side of predicates. The In and Not In operators only support the inline array syntax.
Anyone know how I might do string comparisons in the where clause? It seems that my only option for filtering inside the query is to store seconds-since-epoch in the database and use integer comparisons.

This was a temporary bug with old SQLProvider version and it should be working now. If not, please open a new issue to the GitHub repository: https://github.com/fsprojects/SQLProvider

Related

Compare Two date "Strings" Sqlite using Nhibernate

I am using SQLite and NHibernate and Im storing my date as Strings on SQLite since I cant store as Date.
Everything was just fine until a need to compare dates.. I tried the following codes:
var initialDate = DateTime.Parse(_InitialDate);
var finalDate = DateTime.Parse(_FinalDate);
return session.QueryOver<Locacoes>()
.Where(c => DateTime.Parse(c.InitialDate) >= initialDate )
.Where(c => DateTime.Parse(c.FinalDate) <= finalDate).List();
but I got an exception on the first "Where": "a variable 'c' of type 'Locacoes' is referenced on scope '', but it is not defined".
How can I compare date on SQLite using NHibernate?
I've tried many things with above code, but didnt work.
Edit: Its not duplicate, the error can be the same, but the result is different
First, while Sqlite likes to pretend everything is a string, that should be considered a storage format and NO REASON why your object model should use strings to hold date values. Your object model should of course type the properties as DateTime or DateTimeOffset. Then configure your NHibernate mappings properly to map the values to what SQLite can handle (actually I think NHibernate would handle that automatically if you just tell it to use the SQLiteDialect).
Second, I don't think QueryOver() can handle things like DateTime.Parse(). Don't confuse QueryOver() with Linq2NHibernate (the Query() method), which have more advanced expression interpretation abilities. On the other hand, you no longer need to use Parse() when you begin to use correct types in your object model.
At least if you use LINQ, it should be able to handle DateTime.Date for SQLite, if you need it:
session.Query<Locacoes>()
.Where(l => c.InitialDate.Date >= initialDate)
Of course, you would only need to put Date in there if there is a non-zero time-of-day component that you need to ignore.

Difference in these 2 queries in TERADATA

SEL * FROM TABLE WHERE a=10
VS
SEL * FROM TABLE WHERE a='10'
Here a is BIGINT, Explain plan does not show any difference, how teradata handles this and any difference in these query ?
Teradata automatically applies a datatype conversion if you compare different datatypes (usually but not always).
Whenever a string is compared to a number the string will be converted to a FLOAT, which is the most flexible numeric format.
In your case this conversion was already done by the parser, so the optimizer didn't know 10 was s string before.
If you do it the other way:
SEL * FROM TABLE WHERE a=10 -- column a is a character
you can spot this cast in explain:
"(table.last_name (FLOAT, FORMAT '-9.99999999999999E-999'))= 1.00000000000000E 001"
Sometimes this automatic conversion is convenient, but in a case like that it's really bad: No index can be used and all existing statistics are lost. So you better know you datatypes :-)
This (FLOAT, FORMAT '-9.99999999999999E-999')) in Explain is one of the first things I check if a query performs badly.

Sqlite C/C++ API - Get timestamp value with select query

I use sqlite3 C/C++ API to retrieve rows from a table using SELECT query. I don't see any sqlite3_column_timestamp() to retrieve a timestamp column value after sqlite3_step().. How to get timestamp values ?
SQLite does not have a special timestamp data type.
When you want to use any of SQLite's date and time functions, you have to store timestamps in one of the formats supported by them, i.e., a string like YYYY-MM-DD HH:MM:SS or HH:MM:SS, a julian date number, or a Unix timestamp number.
You can declare a table column type as DATETIME, but SQLite will just ignore that type; SQLite always allows to put values of any type in any column. Such a declaration would be useful only as documentation.
The column/value accessors will only have types corresponding to the data types they support directly (NULL, INTEGER, REAL, TEXT, BLOB).
You would use the TEXT access to get/set the column value of dates.
There are some helper functions within SQL that they provide that let you to handle them in your queries.
I am not familiar with SQLite Manager, but I would assume that it is only reporting the data type that the table was declared with.
When parsing CREATE statements, sqlite understands the intention of many well supported datatypes and automatically maps them to what is appropriate for its internal storage structure. VARCHAR would be mapped to TEXT, for instance. I assume the column was declared DATETIME and sqlite just internally mapped it to TEXT.

Declaring data types in SQLite

I'm familiar with how type affinity works in SQLite: You can declare column types as anything you want, and all that matters is whether the type name contains "INT", "CHAR", "FLOA", etc. But is there a commonly-used convention on what type names to use?
For example, if you have an integer column, is it better to distinguish between TINYINT, SMALLINT, MEDIUMINT, and BIGINT, or just declare everything as INTEGER?
So far, I've been using the following:
INTEGER
REAL
CHAR(n) -- for strings with a known fixed with
VARCHAR(n) -- for strings with a known maximum width
TEXT -- for all other strings
BLOB
BOOLEAN
DATE -- string in "YYYY-MM-DD" format
TIME -- string in "HH:MM:SS" format
TIMESTAMP -- string in "YYYY-MM-DD HH:MM:SS" format
(Note that the last three are contrary to the type affinity.)
I would recommend not using self-defined types. I have observed in version 3.5.6 that types not already defined could sometimes cause an INSERT command to be refused. Maybe 1 out of 1000. I don't know if this was addressed since.
In any case, there is no sizing advantage in typing a column TINYINT or SMALLINT. The only advantage would be outside SQLite, for either parsing your column types with another program or to satisfy your personal need for tidiness. So I strongly recommend using the base types defined by SQLite and sticking to those.
Since SQLite is typeless, use whatever types make it easier for you to see what the schema looks like. Or you can match the types to your codebase.
I'm going to go with Kevin on this one. In short, knock yourself out. Make up brand new areas of mathematics if it suits your schema. Use the classnames of your ORM. Or name every type (except the PRIMARY KEY INTEGER ones) for ex-girlfriends. In the end SQLite is more about how you access and use the data.

How to store and get datetime value in SQLite

My table contains Birthdate field which has datatype as datetime.
I want to get all records having birthday today.
How can I get it?
Try this query:
SELECT * FROM mytable
WHERE strftime('%m-%d', 'now') = strftime('%m-%d', birthday)
Having a special datetime type has always seemed like unnecessary overhead to me, integers are fast, flexible, and use less space.
For general datetime values use Unix Epoch timestamps. Easy to work with, extremely flexible, as well as timezone (and even calender!) agnostic. (I recently wrote an article on using them, which I really have to plug...)
That said, if you're only interested in dates in the Gregorian calendar you may want to use a large integer in the following format: YYYYMMDD, eg 19761203. For you particular usage you could even create a four digit integer like MMDD, say 1703 — that's got to result in fast selects!
SQLite has very poor support for storing dates. You can use the method suggested by Nick D above but bear in mind that this query will result in full table scan since dates are not indexed correctly in SQLite (actually SQLite does not support dates as a built-in type at all).
If you really want to do a fast query then you'll have to add a separate (integral) column for storing the birth day (1-31) and attach an index for it in the database.
If you only want to compare dates then you can add a single (INTEGER) column that will store the date UTC value (but this trick won't allow you to search for individual date components easily).
Good Luck

Resources