I wish to query for
MyDate= '2013-07-08'
From the following records
MyDate
2013-07-08 09:15:21
2013-07-08 09:15:48
2013-07-09 09:20:39
I have come up with some ugly stuff :
MyDate > '2013-07-07 23:59:59' AND MyDate < '2013-07-09 00:00:01'
Is there a better/simple/elegant way to do this?
Use DATE() to isolate the date portion of the datetime expression.
WHERE DATE(MyDate) = '2013-07-08'
If your trying to compare dates use this. If not disregard.
This may not be the most perfect way but, i have used this in the past. Basically i would format both dates so they can be used with a greater than or equal to statement(YEAR/MONTH/DAY).
SELECT * FROM table
WHERE MyDate > DATE_FORMAT(2013-07-07 23:59:59, '%Y%m%y')
AND MyDate < DATE_FORMAT(2013-07-09 00:00:01, '%Y%m%y')
The normative pattern to matching the date portion of a DATETIME in a predicate (e.g. a WHERE clause) is:
WHERE MyDate >= '2013-07-08'
AND MyDate < '2013-07-08' + INTERVAL 1 DAY
When no time component is supplied, MySQL uses midnight as the time component, so there's no need to supply a time component of midnight. The bare column references in the predicate allow for MySQL to consider making efficient range scan on an index on the MyDate column.
For completeness, we'll note that it's also possible to use a ETWEEN operator. But because the "high side" comparison with the BETWEEN is a "less than or equal to", to get just values with date component of a single day, we'd need to back up the smallest fraction of time, which for a DATETIME is a single second:
WHERE MyDate BETWEEN '2013-07-08'
AND '2013-07-08' + INTERVAL 1 DAY + INTERVAL -1 SECOND
(If we had a datatype that had a finer resolution, we'd want to step back from the next day by that smallest unit of resolution.)
To avoid that issue, how fine a resolution is on a given datetime/timestamp datatype (more of an issue with other databases such as SQL Server than MySQL), I just have a preference of the former pattern, using a predicate like:
dateexpr >= midnight and dateexpr < midnight of next day
That's unambiguous, and there's no possible way to have a time value of 23:59:59.997 to be missed, and no possibility of getting exactly at midnight of the next day included.
Because the default time component, when none is supplied, is midnight, the first query predicate is equivalent to:
WHERE MyDate >= '2013-07-08 00:00:00'
AND MyDate < '2013-07-08 00:00:00' + INTERVAL 1 DAY
I think all those extra zeros to explicitly specify a time value of midnight are unnecessary clutter.
Related
Is there a way I can make MySQL return 1 instead of 0 for SELECT NOW() = '2016-10-10' without casting (CAST('2016-10-10' AS DATE)) or converting to date (DATE('2016-10-10')).
My real case scenario is a comparison between a DATE and a DATETIME column. I want to JOIN on those columns, but that's possible only if I can make MySQL compare only the date, ignoring the time.
I can't do the cast/convert because that is very expensive ( Slow query performance left joining a view ).
It's not the '2016-10-10' string that you need to cast (since it is a valid date literal), but NOW().
NOW() returns your current timestamp, with hours, minutes and seconds. While '2016-10-10' is interpreted as '2016-10-10 00:00:00'. Which, presumably is not equal to the current time.
So
SELECT DATE(NOW()) = '2016-10-10'
UPD:
I can make MySQL compare only the date, ignoring the time.
For the comparison coldate = coldatetime you can compare on range, like:
coldate <= coldatetime AND coldate + INTERVAL 1 DAY > coldatetime
Depending on your actual case it may or may not be beneficial.
I have a MySQL DB table with multiple date type fields. I need to do different SELECT queries on this table but I am not sure which way is the best to find records from the same month.
I know I can do the following:
SELECT *
FROM table
WHERE MONTH(somedate) = 5
AND YEAR(somedate) = 2015
But I keep reading that isn't efficient and that I should go with using actual dates, i.e.
SELECT *
FROM table
WHERE somedate BETWEEN '2015-05-01' AND '2015-05-31'
However, all I would have is the month and the year as variables coming in from PHP. How do I easily and quickly calculate the last day of the month if I go with second option?
Don't calculate the last day of the month. Calculate the first day of the next month instead.
Your query can be like this
WHERE t.mydatetimecol >= '2015-05-01'
AND t.mydatetimecol < '2015-05-01' + INTERVAL 1 MONTH
Note that we're doing a less than comparison, not a "less than or equal to"... this is very convenient for comparing TIMESTAMP and DATETIME columns, which can include a time portion.
Note that a BETWEEN comparison is a "less than or equal to". To get a comparison equivalent to the query above, we'd need to do
WHERE t.mydatetimecol
BETWEEN '2015-05-01' AND '2015-05-01' + INTERVAL 1 MONTH + INTERVAL -1 SECOND
(This assumes that the resolution of DATETIME and TIMESTAMP is down to a second. In other databases, such as SQL Server, the resolution is finer than a second, so there we'd have the potential of missing a row with value of '2015-05-31 23:59:59.997'. We don't have a problem like that with the less than the first day of the next month comparison... < '2015-06-01'
No need to do the month or date math yourself, let MySQL do it for you. If you muck with adding 1 to the month, you have to handle the rollover from December to January, and increment the year. MySQL has all that already builtin.
date('t', strtotime("$year-$month-01")) will give days in the month
I am trying to get data from a database between 8PM (say, today) and 2AM tomorrow.
I have been using clauses such as where hour(date_field)>=20 and hour(date_field) <23 to obtain data in the same day.
Here the date_field is datetime
All I want is to be able to tell SQL to get data after 8PM today, increment the datefield and then get data till 2AM tomorrow.
Any help will be appreciated.
The normal pattern for retrieving rows based on a datetime range is perform comparisons on the bare column, comparing the column value to constants derived from expressions.
To get rows for a single contiguous range, 8PM today to 2AM tomorrow, for example:
WHERE t.date_column >= DATE(NOW()) + INTERVAL 20 HOUR
AND t.date_column < DATE(NOW()) + INTERVAL 26 HOUR
To unpack that a little bit: NOW() returns current datetime, the DATE() function truncates the time portion to midnight, then we add back in enough hours to get '8PM today', or enough hours to get '2AM tomorrow'.
If you are meaning to retrieve multiple "8PM to 2AM" periods, for a whole series of days.
First, you'd want an upper and lower bound of the date_column to be retrieved (unless you want every possible date)
WHERE t.date_column >= '2014-08-01 20:00:00'
AND t.date_column < '2014-10-02 02:00:00'
From that, we need to filter out all of the rows that aren't between 8PM and 2AM. One convenient way to do that would be to "subtract" two hours from the datetime col, and check for hour >= 6PM.
AND HOUR(t.date_column + INTERVAL -2 HOUR) >= 18
Note that the expression involving date_column will need to be evaluated for EVERY row in the table, unless there are some other predicates that filter rows out. With a suitable index available, MySQL can use an index range scan operation for predicates of the form date_column >= const and date_column < const. (It can't do that when the column is wrapped in a function or expression.)
It's not a one-of, not only one particular Tuesday, so I won't use time stamps.
I mean something like "every Tuesday from 10am to 11am". What's the best way to store this to make it easy to check from my (Delphi) application if the current time is between those permitted times?
Sounds like the time range would simply be an attribute of whichever primary object you are working with, as such you could add a separate table to store the time range data, something like:
object_time_range
id
object_id
day
hour_start
hour_end
frequency_id
-- Update --
In hindsight I would probably abstract hour from the column names in favor of time, just in case you need to consider alternative time frames. And day should be day_id, even though its a static list, I always like going with ints in this situation.
object_time_range
id
object_id
day_id
time_start
time_end
frequency_id
Store the variable as datetime or timestamp,
you can use mysql date functions such as
date_format and date_add
to get the rows which fall within required dates and time
if you store it as text it would be very difficult.
E.g To get rows for the past one day
select * from tableName
where dateField > date_add(now(),interval -1 day) and
dateField < now()
rows for the past one Week
select * from tableName
where dateField > date_add(now(),interval -1 week) and
dateField < now()
Check date_add funciton
I have a table 't' with date(yyyy-mm-dd), hour(1-12), minute(00-59), ampm(a/p), and timezone(pst/est) fields.
How can I select the rows that are <= now()? (ie. already happened)
Thank you for your suggestions!
edit: this does it without attention to the hour/minute/ap/tz fields:
SELECT * FROM t.date WHERE date <= now()
Here's one way to do it - combine all your seconds, minutes, etc into a date and compare to NOW(), making sure you do the comparison in the same time-zone. (Untested):
SELECT *
FROM t
LEFT JOIN y ON t.constant=y.constant
WHERE CONVERT_TZ(STR_TO_DATE(CONCAT(date,' ',hour,':',minute,' 'ampm),
'%Y-%m-%d %l:%i %p' ),
timezone,"SYSTEM") < NOW();
If your hour is 01 - 12 not 1-12 then use %h instead of %l in the STR_TO_DATE.
The STR_TO_DATE tries to stick your date and time columns together and convert them into a date.
The CONVERT_TZ(...,timezone,"SYSTEM") converts this date from whatever timezone is specified in the timezone column to system time.
This is then compared to NOW(), which is always in system time.
As an aside, perhaps you should make a single column date using MySQL's date datatype, as it's a lot easier to do arithmetic on that!
For reference, here is a summary of very useful mysql date functions where you can read up on those featuring in this answer.
Good luck!
SELECT * FROM t
WHERE `date`<=DATE_SUB(curdate(), INTERVAL 1 DAY)
OR (
`date`<=DATE_ADD(curdate(), INTERVAL 1 DAY)
AND
CONVERT_TZ(CAST(CONCAT(`date`,' ',IF(`hour`=12 AND ampm='a',0,if(ampm='a',`hour`,`hour`+12)),':',`minute`,':00') AS DATETIME),'GMT',`timezone`)<=NOW()
)
Rationale for date<=DATE_[ADD|SUB](curdate(), INTERVAL 1 DAY):
The fancy conversion is quite an expensive operation, so we don't want it to run on the complete table. This is why we pre-select against an UNCHANGED date field (possibly using an index). In no timezone can an event being more than a day in current timezone's past be in the future, and in no timezone can an event more than a day in the curent timezone's future be in the past.