I am using SQLite for a project and < symbol is not working in the query.
There is a table named Holidays which has a field of datatype datetime.
Suppose the table contains some dates of current year in the column HolidayDate.
SELECT HolidayDate
FROM Holidays
WHERE (HolidayDate >= '1/1/2011')
AND (HolidayDate <= '1/1/2012')
The < symbol in the above query is not working. > symbol in the above query is working well.
Please help me.
Try:
SELECT HolidayDate
FROM Holidays
WHERE HolidayDate >= date('2011-01-01')
AND HolidayDate <= date('2012-01-01')
(date format must be YYYY-MM-DD)
There is no datetime datatype in sqlite.
Sqlite only has 4 types:
integeral number
floating-point number
string (stored either as utf-8 or utf-16 and automatically converted)
blob
Moreover, sqlite is manifest-typed, which means any column can hold value of any type. The declared type is used for two things only:
inserted values are converted to the specified type if they seem to be convertible (and it does not seem to apply to values bound with sqlite_bind_* methods at all)
it hints the indexer or optimizer somehow (I just know it has trouble using indices when the column is not typed)
Even worse, sqlite will silently accept anything as type. It will interpret it as integeral type if it starts with "int", as string if it contains "char" or "text", as floating-point number if it is "real", "double" or "number" and as blob if it's "blob". In other cases the column is simply untyped, which poses no problem to sqlite given how little the typing means.
That means '1/1/2011' is simply a string and neither dates in format 'mm/dd/yyyy' nor dates in format 'dd/mm/yyyy' sort by date when sorted asciibetically (unicodebetically really).
If you stored the dates in ISO format ('yyyy-mm-dd'), the asciibetical sort would be compatible with date sort and you would have no problem.
Related
How can I convert timestamps to dates in SQLite?
The following code only produces a Timestamp column and a Date columns with NULL values. The the SQL code needs to convert from a "08/28/2020 8:00" format.
SQL CODE:
'''Select Timestamp, strftime('%m-%d-%Y', Timestamp) as Date
FROM Room_Data'''
The SQLite documentation is pretty clear, but I can't seem to get the desired result.
The strftime is meant to format a date, rather than perform conversion.
In the meantime you could try something like that to gather the pieces:
SELECT Timestamp,
SUBSTR(c,7,4) || '-' || SUBSTR(Timestamp,1,2) || '-' || SUBSTR(Timestamp,4,2) as Date
FROM Room_Data
Since SQlite doesn't really have the concept of a date, unlike other DBMS, the best choice would be to convert your dates to integer, either as Unix timestamps or in string form (YYYY-MM-DD) but storing dates as integer like 20201010 would be acceptable too.
NB: be careful with names like Timestamp or Date, they are reserved keywords in many programming languages and DBMSes.
The original code won't work in Windows 10 for some reason. Trying this from a Linux distro (Kubuntu, in this case) seems to resolve the issue. In Windows, the date needs to be converted to a '2020-01-01' format to actually work.
SQLite is amazing, but not sure why functionality changes for Windows 10. Feel free to comment if you know more about the differences.
can you please help me why this code does not work?
I dont understand why the result include "2017".
SQLLITE
QUERY
SELECT issue_date as count FROM tablename where issue_date >= "08/08/2016" and issue_date < "09/01/2016"
Result
"08/08/2017"
"08/11/2017"
"08/18/2017"
"08/18/2017"
"08/22/2017"
"08/22/2017"
"08/28/2017"
"08/31/2017"
Create query
CREATE TABLE tablename (
issue_date datetime text not null
}
Insert query
INSERT INTO tablename (issue_date) values ("08/31/2017");
You are storing your dates in a non ANSI compliant format. As there is no formal date type in SQLite, and all dates are essentially stored as strings, your current date comparison will behave and sort as if you are comparing to text. It won't work, because you have the month first, followed by the day, followed by the year. To get text comparisons of dates to work correctly, use a format something like this:
yyyy-mm-dd
You should change the format you use to store dates, but one workaround would be to build the issue date in the correct format and then do the comparison, also against a date string in the same correct format:
SELECT
issue_date AS count
FROM tablename
WHERE
SUBSTR(issue_date, 7, 4) || '-' ||
SUBSTR(issue_date, 1, 2) || '-' ||
SUBSTR(issue_date, 4, 2) BETWEEN '2016-08-08' AND '2016-09-01'
SQLite's data types does not have a real DATETIME type. It only has NULL, INTEGER, REAL, TEXT and BLOB. Any other type is converted to these, so what it is doing in your case is storing those values as strings, and this comparing as strings.
I personally prefer to store the dates as UNIX timestamps (hence integers) to avoid complicating the SQL queries and simplify the whole thing (although the values in database will become less human-readable).
Because you specified the query with AND. So it matches your query. Use BETWEEN expression.
expression BETWEEN value1 AND value2;
What does the following SQL statement do in case of SQLite?
CREATE TABLE foo(id INTEGER PRIMARY KEY, time STRFTIME);
Note that the time column has the STRFTIME type which is not listed in the documentation.
I guess that the following INSERT works without any errors
sqlite> INSERT INTO foo (time) VALUES('text');
sqlite> SELECT * FROM foo;
1|text
because of this:
3.1. Determination Of Column Affinity
The affinity of a column is determined by the declared type of the
column, according to the following rules in the order shown:
If the declared type contains the string "INT" then it is assigned
INTEGER affinity.
If the declared type of the column contains any of the strings "CHAR",
"CLOB", or "TEXT" then that column has TEXT affinity. Notice that the
type VARCHAR contains the string "CHAR" and is thus assigned TEXT
affinity.
If the declared type for a column contains the string "BLOB" or if no
type is specified then the column has affinity BLOB.
If the declared type for a column contains any of the strings "REAL",
"FLOA", or "DOUB" then the column has REAL affinity.
5. Otherwise, the affinity is NUMERIC.
and this:
A column with NUMERIC affinity may contain values using all five
storage classes. When text data is inserted into a NUMERIC column, the
storage class of the text is converted to INTEGER or REAL (in order of
preference) if such conversion is lossless and reversible. For
conversions between TEXT and REAL storage classes, SQLite considers
the conversion to be lossless and reversible if the first 15
significant decimal digits of the number are preserved. If the
lossless conversion of TEXT to INTEGER or REAL is not possible then
the value is stored using the TEXT storage class. No attempt is made
to convert NULL or BLOB values
Am I right?
If you want to implement a new type, it still must be stored internally in one of the sqlite primitive types. You then must provide functions to convert from python to sqlite and vice versa.
Here are the steps to perform:
Use sqlite3.register_adapter to specify how to convert python type to sqlite. Although you could convert to one of sqlite internal/primitive types (text, integer, real, blob and null), you should use TEXT to be able to convert back (see next point).
Use sqlite3.register_converter to specify how to convert from sqlite internal representation back to the python type.
When calling connect(), specify the detect_types=sqlite3.PARSE_DECLTYPES argument.
When you create a table, use the custom type name.
Note: the register_converter documentation says that you must convert from a bytestring.
Here is an example to implement a custom 'date' type:
import sqlite3
from datetime import date
def date_to_str(d): # for python to sqlite
return '%04d%02d%02d' % ( d.year, d.month, d.day )
def str_to_date(s): # for sqlite to python
y=int(s[0:4])
m=int(s[4:6])
d=int(s[6:8])
return date(y,m,d)
sqlite3.register_adapter(date,date_to_str)
sqlite3.register_converter('date',str_to_date)
WEEKDAYS = {
0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5:"Sat",6:"Sun"
}
def test():
s = sqlite3.connect('myfile.dat', detect_types=sqlite3.PARSE_DECLTYPES)
c = s.cursor()
c.execute('create table t1(id integer primary key, d1 date)')
c.execute('insert into t1 values(?,?)', (1, date(2016,9,24)))
c.execute('insert into t1 values(?,?)', (2, date(2000,1,1)))
s.commit()
for r_id, r_date in c.execute('select id,d1 from t1 order by d1'):
print r_id, r_date, r_date.year, r_date.month, r_date.day, WEEKDAYS[r_date.weekday()]
if __name__ == '__main__':
test()
While I was typing my answer, I read the accepted answer, and realized this was not your question. However, if this can help other people...
Yes; STRFTIME has exactly the same affinity as FLUFFY BUNNIES, i.e., numeric.
I insert my date/time data into a CHAR column in the format: '6/4/2015 2:08:00 PM'.
I want that this should get automatically converted to format:
'2015-06-04 14:08:00' so that it can be used in a query because the format of DATETIME is YYYY-MM-DD hh:mm:ss.fffff.
How to convert it?
Given that you've stored the data in a string format (CHAR or VARCHAR), you have to decide how to make it work as a DATETIME YEAR TO SECOND value. For computational efficiency, and for storage efficiency, it would be better to store the value as a DATETIME YEAR TO SECOND value, converting it on input and (if necessary) reconverting on output. However, if you will frequently display the value without doing computations (including comparisons or sorting) it, then maybe a rococo locale-dependent string notation is OK.
The key function for converting the string to a DATETIME value is TO_DATE. You also need to look at the TO_CHAR function because that documents the format codes that you need to use, and because you'll use that to convert a DATETIME value to your original format.
Assuming the column name is time_string, then you need to use:
TO_DATE(time_string, '%m/%d/%Y %I:%M %x') -- What goes in place of x?
to convert to a DATETIME YEAR TO SECOND — or maybe DATETIME YEAR TO MINUTE — value (which will be further manipulated as if by EXTEND as necessary).
I would personally almost certainly convert the database column to DATETIME YEAR TO SECOND and, when necessary, convert to the string format on output with TO_CHAR. The column name would now be time_value (for sake of concreteness):
TO_CHAR(time_value, '%m/%d/%Y %I:%M %x') -- What goes in place of x?
The manual pages referenced do not immediately lead to a complete specification of the format strings. I think a relevant reference is GL_DATETIME environment variable, but finding that requires more knowledge of the arcana of the Informix product set than is desirable (it is not the first thing that should spring to anyone's mind — not even mine!). If that's correct (it probably is), then one of %p and %r should be used in place of %x in my examples. I have to get Informix (re)configured on my machine to be able to test it.
I'm trying to do a query like this on a table with a DATETIME column.
SELECT * FROM table WHERE the_date =
2011-03-06T15:53:34.890-05:00
I have the following as an string input from an external source:
2011-03-06T15:53:34.890-05:00
I need to perform a query on my database table and extract the row which contains this same date. In my database it gets stored as a DATETIME and looks like the following:
2011-03-06 15:53:34.89
I can probably manipulate the outside input slightly ( like strip off the -5:00 ). But I can't figure out how to do a simple select with the datetime column.
I found the convert function, and style 123 seems to match my needs but I can't get it to work. Here is the link to reference about style 123
http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.ase_15.0.blocks/html/blocks/blocks125.htm
I think that convert's slightly wrongly documented in that version of the docs.
Because this format always has century I think you only need use 23. Normally the 100 range for convert adds the century to the year format.
That format only goes down to seconds what's more.
If you want more you'll need to past together 2 x converts. That is, past a ymd part onto a convert(varchar, datetime-column, 14) and compare with your trimmed string. milliseconds comparison is likely to be a problem depending on where you got your big time string though because the Sybase binary stored form has a granularity of 300ms I think, so if your source string is from somewhere else it's not likely to compare. In other words - strip the milliseconds and compare as strings.
So maybe:
SELECT * FROM table WHERE convert(varchar,the_date,23) =
'2011-03-06T15:53:34'
But the convert on the column would prevent the use of an index, if that's a problem.
If you compare as datetimes then the convert is on the rhs - but you have to know what your milliseconds are in the_date. Then an index can be used.