So, I have a following SQLite query:
SELECT datetime('2013-10-07 08:23:19.111') = datetime('2013-10-07 08:23:19.222')
To my surprise the result that I get is ... 1 (true). No matter what values I put after the dot, it is always true when fractional values are different.
According to docs:
In formats 4, 7, and 10, the fractional seconds value SS.SSS can have one or more digits following the decimal point. Exactly three digits are shown in the examples because only the first three digits are significant to the result, but the input string can have fewer or more than three digits and the date/time functions will still operate correctly.
Is there some sort of mistake or is there something I don't understand?
The page you linked to says:
The datetime() function returns "YYYY-MM-DD HH:MM:SS".
If you know that your values already are exactly in the correct format, just compare the strings directly. Otherwise, replace datetime() with strftime() with %f to convert the values into the format you want.
Related
I am a somewhat newbie to SQLite (and KMyMoney). KMyMoney (an open source personal finance manager) allows one-click exporting data into an SQLite database.
On browsing the SQLite database output, the dollar amount data is stored in a table called kmmSplits as several text fields in a strange format based on “value” and “valueFormatted” (see screen shot below). The “value” field is apparently written as a division equation (in a text format) which apparently yields the “valueFormatted” field (again in text format). The “valueFormatted is the correct number amount but the problem is that parenthesis are used to indicate a negative number instead of a simple minus in front of the value. This is apparently an accounting number format, but I don’t know how to parse this into a float value for running calculated SQL queries, etc. The positive values (without parenthesis) are no problem to convert to FLOATS.
I’ve tried using the CAST to FLOAT function but this does not do the division math, nor does it convert parenthesis into negative values (see screen shot).
The basic question is: how to parse a text value containing parenthesis in the “valueFormatted field (accounting money format) into a common number format OR, alternatively, how to convert a division equation in the “value” field to an actual calculation.
Use a CASE expression to check if valueFormatted is a numeric value inside parentheses and if it is multiply -1 with the substring starting from the 2nd char (the closing parenthesis will be discarded by SQLite during this implicit type casting):
SELECT *,
CASE
WHEN valueFormatted LIKE '(%)' THEN (-1) * SUBSTR(valueFormatted, 2)
ELSE valueFormatted
END AS value
FROM kmmSQLite;
Or, replace '(' with ''-'' and add 0 to covert the result to a number:
SELECT *,
REPLACE(valueFormatted, '(', '-') + 0 AS value
FROM kmmSQLite;
When using sprintf() when I want to format a number with a fixed number of digits, I have to use format strings like "%.3f" or "%2d". Now the Qt-manual says, I have to use QStrings::arg()-function instead of sprintf():
QString("%1").arg(QString::number(1.3));
So how do I specify the number of digits to be shown in resulting string? Thanks :-)
QString::arg
You can specify the formatting with QString::arg like:
%.3f: QString("%1").arg(1.3, 0, 'f', 3): where the second argument is the field-width (minimum width of the resulting string, 0 here), the third is the format of the number, (in this case f means use no scientific notation), and the fourth is the precision (3 number of decimal places).
%2d: QString("%1").arg(42, 2).
Note: When using QString::arg you must be careful on using the adequate data type. For example, if you want to format the number 50 with one zero decimal, you must use QString("%1").arg(50.0, 0, 'f', 1). If you use QString("%1").arg(50, 0, 'f', 1) instead (note 50 is an integer), code won't compile due to a conflict of arguments.
This is the preferred way to do it in Qt, specially if the formatting string has to be localized. One of the main reasons is that the placeholders for values have an index (%1, %2...), allowing them to be in any order in the string and keeping their semantics (you may need to change order in some languages).. When using sprintf-like functions the order of the arguments matters.
QString::asprintf
Nevertheless, and though not recommended in new Qt code, you can use the sprintf-like QString::asprintf (do not use QString::sprintf which is deprecated). For example, QString::asprintf("%.3f", 1.3).
Trying to return field [doc] that have no letters. Results are all over the place.
SELECT Right([doc],4) AS ex1, IsNumeric([ex1]) AS ex2
FROM stat_converted;
The query returns two fields as it should but not evaluating correctly. Results with all numbers and others that are all letters are coming back as True(-1).
I also tried building a temp table and then applying IsNumeric to that with same results.
I also built a small test DB and the logic works so I am really confused.
IsNumeric will match things like "2E+1" (2 times ten to the power of 1, i.e. 20) as that is a number in scientific format. "0D88" is also a number according to IsNumeric because it is the double-precision (hence the "D") version of "0E88".
You could use LIKE '####' to match exactly four digits (0-9).
If you had more complex match requirements, say a variable quantity of digits, you would be interested in Expressing basic Access query criteria as regular expressions.
I pull data from a websource and it returns time in the format 'YYYY-MM-DDTHH:MM:SS.SSSZ'. Since I would be doing a lot of comparisons on this column, I thought it would be best to store them as the number of millliseconds since epoch (I need millisecond precision!!). What would be the best way to convert the incoming datetime string to number of milliseconds?
I tried to use
strftime('%s', datetimeString) - gives back the number of seconds since epoch till datetimeString
strftime('%f', datetimeString) - gives back only the SS.SSS part!!
I'm guessing it has something to do with SQLite not having actual Date or Datetime types (section 1.2). Instead it formats them as one of:
an ISO8601 string (TEXT type)
a floating point number of days (REAL type)
an integer number of seconds since the epoch time (INTEGER type)
The REAL data type may not have enough precision to store a date, time, and fractional seconds in a single field.
It seems the answer is one of:
store them as two separate fields, the datetime in one, and the fractional seconds in another
do the integer number of milliseconds calculation yourself and store the integer result in a single column, so long as the maximum level of fractional second precision you need will fit in a signed integer of 8-bytes or fewer (the maximum size for the INTEGER type in SQLite3)
switch databases to a DBMS that supports real date/datetime types
Without switching your DB, and if you never need sub-millisecond precision, then I'd at least try the "manual calculation + single integer column" solution and see if it works.
I kind of assumed it was a string, so I compared it as a string, but not surprisingly it failed. I believe thats how it works in Mysql. I could be wrong as I haven't worked on it in a while. In either case, how can I check if dates are equal in SQLite? I will be using it in a WHERE clause.
SELECT a._id, b._id, b.start_date,a.event_name, b.start_time,
b.end_date, b.end_time, b.location FROM events_info b INNER JOIN events a ON
a._id=b.event_id WHERE b.start_time = '6:00';
(added space to make it easier to look at)
SQLite doesn't have a dedicated DATETIME type. Normally what people do is make sure they store the date as a formatted string that is consistent; for example, YYYY-MM-DD hh:mm:ss. If you do so, as long as you're consistent, then you can compare dates directly:
SELECT * FROM a WHERE q_date < '2013-01-01 00:00:00';
This works because even though the comparison is technically an alphabetical comparison and not a numeric one, dates in a consistent format like this sort alphabetically as well as numerically.
For such a schema, I would suggest storing dates in 24-hour format (the above example is midnight). Pad months, days, and hours with zeros. If your dates will span multiple timezones, store them all in UTC and do whatever conversion you need client-side to convert them to the local time zone.
Normally dates and times are stored all in one column. If you have to have them separated for whatever reason, just make sure you dates are all consistent and your times are all consistent. For example, dates should all be YYYY-MM-DD and times should all be hh:mm:ss.
The reason that YYYY-MM-DD hh:mm:ss is the preferred format is because when you go from the largest date interval (years) to the smallest (seconds), you can index and sort them very easily and with high performance.
SELECT * FROM a WHERE q_date = '2012-06-04 05:06:00';
would use the index to hone in on the date/time instead of having to do a full table scan. Or if they're in two separate rows:
SELECT * FROM a WHERE q_date = '2012-06-04' AND q_time = '05:06:00';
The key is to make sure that the dates and times are in a consistent format going into the database. For user-friendly presentation, do all conversion client-side, not in the database. (For example, convert '2012-06-04 05:06:00' to "1:06am Eastern 6/4/2012".)
If this doesn't answer question, could you please post the exact format that you're using to store your dates and times, and two example dates that you're trying to compare that aren't working the way you expect them to?
Sqlite can not compare dates directly. we need to convert them in seconds as well as integer also.
Example
SELECT * FROM Table
WHERE
CAST(strftime('%s', date_field) AS integer) <=CAST(strftime('%s', '2015-01-01') AS integer) ;
From Datatypes In SQLite Version 3:
1.2 Date and Time Datatype
SQLite does not have a storage class set aside for storing dates and/or times. Instead, the built-in Date And Time Functions of SQLite are capable of storing dates and times as TEXT, REAL, or INTEGER values:
TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
Applications can chose to store dates and times in any of these formats and freely convert between formats using the built-in date and time functions.
If you look at the examples in Date And Time Functions, something like this should get you close to what you want (which, I'm assuming, is 6:00 of the current day):
WHERE b.start_time = date('now', 'start of day', '+6 hours')