I have a table with device data, one of the columns created_ts -> varchar(30)
The problem: this data in this column contains both linux timestamps and varchars for example:
1381148885
and
2012-09-17 22:13:17
How can I query this column for all records with created_ts > 2013-10-01
I'd opt for distinguishing between the string formats (either 'YYYY-MM-DD' or unix timestamp integer) by checking for a dash character.
I'd consider explicitly converting both of those formats to the DATE datatype, using an appropriate conversion. I'd compare the resulting DATE value with the date literal.
Something like this:
WHERE IF(LOCATE('-',t.created_ts,5), -- which format (yyyy-mm-dd or integer)
STR_TO_DATE(t.created_ts,'%Y-%m-%d %T'), -- convert yyyy-mm-dd string to date
FROM_UNIXTIME(t.created_ts) -- convert string as integer to date
) >= '2013-10-01' -- compare to date literal
Another option would be to convert the string column and the date literal to integer values, and do an integer comparison. (Again, two different conversions for the string column, depending on the format.)
NOTE: I included the hh:mm:ss portion in the conversion with the %T.
When no time component is supplied, the time components is assumed to be midnight (zeros) 00:00:00, and that comes into play depending on whether or not we want to consider
'2013-10-01 07:34:55' > '2013-10-01 00:00:00'
OP query has a greater than comparison. I used a greater than or equal to comparison.
This could all be adjusted, depending on the requirements. We want to be aware that if we aren't careful, some values will get "rounded down" to the previous midnight, and then when we do a greater than comparison, what we're really getting is equivalent to >= '2013-10-02'.
My preference is to make it more explicit. It makes it easier for the reader to understand what the query is actually doing.
UPDATE
I had the arguments in the LOCATE function backwards... the string to search for should be the first argument, the string to be searched is second. That's been corrected in the query above.
Something like this:
select * from yourTable
where created_ts > '2013-10-01'
or from_unixtime(created_ts) > '2013-10-01';
Related
I have a table with a Date column. It has a row where my_date column's value is 2017-11-24
SELECT * FROM mytable WHERE my_date = '2017-11-24 00:00:00' returns that row.
While SELECT * FROM mytable WHERE my_date = '2017-11-24 00:00:01' does not.
From mysql doc; this page says
If one of the arguments is a TIMESTAMP or DATETIME column and the
other argument is a constant, the constant is converted to a timestamp
before the comparison is performed. This is done to be more
ODBC-friendly. This is not done for the arguments to IN().
If I am interpreting this correctly, in the second query, the constant on right side would be implicitly casted to Date field
The second page for casting says -
Conversion to a DATE value takes fractional seconds into account and
rounds the time part. For example, '1999-12-31 23:59:59.499' becomes
'1999-12-31', whereas '1999-12-31 23:59:59.500' becomes '2000-01-01'.
The example shows 1999-12-31 23:59:59.499 -> 1999-12-31. I understand explicit casting is preferred, but I am wondering why mysql chose to typecast the column value instead of constant or if there's something else happening here.
I don't think you are interpreting the docs correctly. The first page you quote is about comparing a DATETIME or TIMESTAMP to a constant. You are comparing a DATE to a constant, so this logic should apply:
Conversion of DATE values:
Conversion to a DATETIME or TIMESTAMP value adds a time part of '00:00:00' because the DATE value contains no time information.
So it's like comparing '2017-11-24 00:00:00' = '2017-11-24 00:00:01' which sensibly returns false.
Comparing DATEs to DATETIMEs/TIMESTAMPs is similar to comparing an int to a double in that the implicit conversion applies to the less precise value. You would not expect 42 to match 42.1, and likewise you shouldn't expect 2017-11-24 to match 2017-11-24 00:00:01.
i want to do a count of two columns in mysql. One of the columns is a string but another is a date like 06/08/2017 and when i do my query i get 0 results.
SELECT count(*) FROM `castigos` WHERE inicio_normal=05/06/2017 AND cod_emplazamiento=1
I have entries of that data but its dont show me anything. Maybe the type of data in the date is wrong?
What should i do?
Add the date field to your select and group by it. Otherwise mysql extensions doesn't recognize you want to group by the date and will aggregrate all the results into 1 column. And since you are getting 0 count, you're where clause must not be working.
Your date format seems malformed. usually YYYY/MM/DD format (standard format);
or specify a format using SELECT STR_TO_DATE('17/09/2010','%d/%m/%Y');
MySQL retrieves and displays DATE values in 'YYYY-MM-DD' format. The supported range is '1000-01-01' to '9999-12-31'.
the below uses the implicit casting and default date format to convert the string date to a valid date.
SELECT inicio_normal, count(*)
FROM `castigos`
WHERE inicio_normal='2017/05/06'
AND cod_emplazamiento=1
GROUP BY inicio_normal
Otherwise its doing math and comparing that date to the number stored for the date.
Understand dates should be stored in a date datatype and when you query dates you're passing in a string that is being cast to a date datatype for comparison. So you need to use the standard format, or cast your string to a date so the db engine knows how to convert your format to a date.
Try this :
SELECT count(*) FROM `castigos` WHERE inicio_normal="05/06/2017" AND cod_emplazamiento=1 GROUP BY inicio_normal
WHERE inicio_normal=05/06/2017
If you divide 3 by 6 then by 2017 you get a very small value indeed. OTOH if you reformat this as a date (e.g. 20170605, if you gave us a European formatted date - dd/mm/yyyy) then your query will find the rows you showed us.
how to return exactly rows between two dates with timestamps
this code didn't return all row between 01-04 and 07-05
so what is the problem and why it didn't work correctly
and how to select rows between two date with timestamp when i use date
format like this 01-04-2015
SELECT d_send_items.si_id ,
DATE_FORMAT(FROM_UNIXTIME(d_send_items.si_send_date), '%d-%m-%Y')
FROM d_send_items WHERE
DATE_FORMAT(FROM_UNIXTIME(d_send_items.si_send_date), '%d-%m-%Y') BETWEEN '01-04-2015' AND '07-05-2015'
date_format returns a string, so between is using string comparisons to figure out whether the values are between those two you provide.
So, unless your date format is something like yyyy-mm-dd, between is not going to work as you expect.
For example, the date 08-04-2015 is between the two dates 01-04-2015 and 07-05-2015 but the string 08-04-2015 is not between the two strings 01-04-2015 and 07-05-2015, because the most significant portion 08 is beyond the range which terminates at 07....
So you could use:
where
date_format(from_unixtime(d_send_items.si_send_date), '%Y-%m-%d')
between '2015-04-01' and '2015-05-07'
but per-row functions never scale well in relational databases.
If they're proper timestamp fields, I think you can also bypass the conversion and use something like:
where d_send_items.si_send_date >= '01-04-2015'
and d_send_items.si_send_date < '08-05-2015'
(noting the < day following bit for the second conditional since 08-05-2015 is the same as 08-05-2015 00:00:00) assuming MySQL will recognise those date formats as dd-mm-yyyy.
However, even if it doesn't and you have to use some function to turn those string into timestamp values, this is something that would be done once for the whole query rather than (most likely) for every single row.
I need to get all records those equal and less than 2012-12-28 i used bellow query for this,
booking_time is DATETIME field, and there are records less than 2012-12-28 but it returns zero rows.
does anyone has idea ?
SELECT * FROM ctx_bookings WHERE DATE(booking_time)<=2012-12-28 ORDER BY id ASC
Table filed
+---------------------+
| booking_time |
+---------------------+
| 2012-12-20 03:10:09 |
| 2012-12-25 02:10:04 |
+---------------------+
Please anybody know why is this happening ?
wrap the value with single quote and surely it will work
SELECT *
FROM ctx_bookings
WHERE DATE(booking_time) <= '2012-12-28'
ORDER BY id ASC
SQLFiddle Demo
As documented under Date and Time Literals:
MySQL recognizes DATE values in these formats:
As a string in either 'YYYY-MM-DD' or 'YY-MM-DD' format. A “relaxed” syntax is permitted: Any punctuation character may be used as the delimiter between date parts. For example, '2012-12-31', '2012/12/31', '2012^12^31', and '2012#12#31' are equivalent.
As a string with no delimiters in either 'YYYYMMDD' or 'YYMMDD' format, provided that the string makes sense as a date. For example, '20070523' and '070523' are interpreted as '2007-05-23', but '071332' is illegal (it has nonsensical month and day parts) and becomes '0000-00-00'.
As a number in either YYYYMMDD or YYMMDD format, provided that the number makes sense as a date. For example, 19830905 and 830905 are interpreted as '1983-09-05'.
As #Barmar commented, your literal expression 2012-12-28 is evaluated as the arithmetic (2012 - 12) - 28, which equals 1,972.
Per #JW.'s answer, you can quote that expression to obtain a valid date literal (of the first form, above). Alternatively:
whilst still quoting the literal, you could use any other punctuation character (or even no character) as the delimiter between date parts:
WHERE DATE(booking_time) <= '2012_12_28'
WHERE DATE(booking_time) <= '20121228'
you could remove the delimiters and leave your literal unquoted:
WHERE DATE(booking_time) <= 20121228
Note also that using a filter criterion like this, which uses a function (in this case, the DATE() function) over a column, requires a full table scan in order to evaluate that function—it therefore will not benefit from any indexes. A more sargable alternative would be to filter more explicitly over the range of column values (i.e. times) that satisfy your criteria:
WHERE booking_time < '2012-12-28' + INTERVAL 1 DAY
This is equivalent because any time that falls strictly prior to the following day will necessarily have occurred on or before the day of interest. It is sargable because the column is compared to a constant expression (the result of the + operation being deterministic), and therefore an index over booking_time can be traversed to immediately find all matching records.
SELECT * FROM ctx_bookings WHERE DATE(booking_time)<='2012-12-28' ORDER BY id ASC
try this mate
Is it more efficient for me to store dates as INTs and convert to and fro a string representation such as "2010-01-30" or is it alright to store dates as DATE when needing to perform very frequent integer queries such as WHERE Date < 20100130... Are dates internally stored as strings or integers?
DATE is actually only a 3-byte column, as opposed to a normal INT column which is 4 bytes, so are actually smaller. When you do a query on a DATE field, when you're passing in an integer representation of the date (i.e where `date` < 20100210), it will be converted to the 3-byte value and compared that way... Then again, a DATE field will just store dates and no time information.
It's more efficient to store the date as a DATE.
For more info, look here: http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html