mysql select on datetime objects within range - mysql

I have a table 'appointments' that contains, among other things, two datetime fields labeled 'start' and 'end'. I also have date in local time that is converted as a range of a full day into UTC (which is what the SQL table stores the datetimes as). I need to select all the (business) times between 00:00:00 and 08:00:00 UTC that also fall in the range of my local time conversion.
An example, A user in PST (pacific standard time) picks December 1st, 2018. The dates between December 1st at 00:00:00 and December 2nd 00:00:00 are converted to UTC which would be December 1st 08:00:00 to December 2nd 08:00:00. I need to select all appointments between 00:00:00 and 8:00:00 any given day in the previous range (dec 1 - dec 2).
All of my datetimes/queries are in the form 'yyyy-MM-dd HH:mm:ss'.
I know that I can select all of the times between two times rather simply like so:
SELECT start, end
FROM appointment
WHERE start>='2018-12-01 00:00:00'
AND end<='2018-12-02 08:00:00'
But I'm unsure as to how to trim these down to only between business hours.
I'm looking for something like
SELECT start, end
FROM appointment
WHERE (start>='2018-12-01 00:00:00'
AND end<='2018-12-02 08:00:00')
AND (start.substring(11, start.end) >= '00:00:00'
AND end.substring(11, end.end) <= '08:00:00')
Where a call like start.substring(11, start.end) would return the time in 'HH:mm:ss' format

Try using the TIME function in MySQL.
SELECT start, end
FROM appointment
WHERE TIME(start) >= '00:00:00'
AND TIME(end) <= '08:00:00' AND ... //other conditions

Related

Why did MySQL SUM IF quit working in 2021

This code quit working in 2021 after working in 2020:
SELECT name, SUM(CASE WHEN YEARWEEK(prod_date) = YEARWEEK(now()- INTERVAL 1 WEEK) THEN gas_prod ELSE NULL END) AS LastWeek FROM daily_prod GROUP BY name
The code now calculates a larger number than occurred last week. Any reason why a new year would cause this code to work differently?
First, using the sum( case/when ) is a bad choice here. Your query is going against your ENTIRE daily_prod table, EVERY RECORD, but only summing when within the given yeardate() period based on whatever the current date is. Instead of doing that, build out a WHERE clause to just get the records you care about. The YearWeek() function is based on a Sunday to Saturday week schedule. So, for example this week is from Jan 31 at 12:00am (midnight) up to, but not including Feb 7th at 12:00am midnight. This includes everything up to Feb 6th at 11:59:59pm.
So, by doing embedded MySQL variables you can build as a "from" table alias as I will show. First, lets get whatever the current NOW() is which is inclusive of hour/minute/second and strip down to just the date portion. Ex: 2021-02-04 # 01:42am truncates down to just 2021-02-04 12:00am
select cast( now() as date )
From that, now, we need to go to the first of the week, represented as Sunday. For this, we use the day of the week and subtract 1 so it is a zero-based value where Sunday = 0, Saturday = 6. So Thursday, normally returns 5, subtract 1 = 4. February 4 - 4 days = Jan 31 which is the first of the current week.
select date_sub( [result of sql above], interval dayofweek( [result of sql above] ) -1 day )
Now, since you want the entire week of data, in this scenario, your data would be from Jan 31 at 12:00am in the morning up to Feb 6th (Saturday) at 11:59:59PM. So, take the above beginning of the week and add 1 week to it bringing you to Feb 7th.
select date_add( [result of 2nd query], interval 1 week )
Yes, this is intentional because now in your final query you can query LESS THAN Feb 7th.
So, by using a where on your data source, you only get those records, AND, if your table has an index on the transaction date, can be optimized for the query. To use inline variables, we can just use the results of these as part of the query such as:
SELECT
dp.name,
SUM( dp.gas_prod ) CurrwntWeekGas
FROM
daily_prod dp,
( select
-- first, variable #nd = Now as a date only
#nd := cast( now() as date ),
-- from the #nd, subtract 0-based day of week
-- example: Thursday is 5th day of week -1 = 4 days to subtract
#fow := date_sub( #nd, interval dayofweek( #nd ) -1 day ),
-- finally from the first of the week, add 1 week to the END point for the query
#nextWeek := date_add( #fow, interval 1 week )
) sqlvars
where
-- only grab records greater or equal to the first day of the week
dp.prod_date >= #fow
-- and ALSO LESS then the the beginning of NEXT week
AND dp.prod_date < #nextWeek
GROUP BY
dp.name
So, as the from clause alias "sqlvars" is processed, it creates the 3 "#" variables to define the beginning of week and beginning of NEXT week values. Those can then be applied to the where clause and limit just the records you need, not the full table.
If you really want the results of the prior week from the week you are in... Ex: the total from Jan 24th to Jan 30th since the current week has not completed, then just change your dayofweek() -1 to dayofweek() -8 to get the entire prior week, not the CURRENT week you are in the middle of now.

How do I query in mysql to select beetween 4 PM and 10 PM for a whole month

So I have a problem to select data from my database. I want to select data with recorded time between 4 PM and 10 PM for a whole month. If it's isn't possible should I query per day for a whole month?
Assuming mydt column is DATETIME or TIMESTAMP datatype,
we could do something like this:
FROM t
WHERE t.mydt >= '2019-09-01'
AND t.mydt < '2019-09-01' + INTERVAL 1 MONTH
AND DATE_FORMAT(t.mydt,'%H') >= '16'
AND DATE_FORMAT(t.mydt,'%H') < '22'
The first two conditions restrict values to the month of September 2019.
The last two conditions restrict the "hour" portion of the datetime, time values from 16:00:00 thru 21:59:99
If we also want to include 22:00:00, we can use '%T' as format model in DATE_FORMAT and do a less than or equal to comparison
AND DATE_FORMAT(t.mydt,'%T') >= '16:00:00'
AND DATE_FORMAT(t.mydt,'%T') <= '22:00:00'

Select Range of Items by Year and Month

I'm attempting to create a select statement which gets items by year and month.
This is what I have so far:
SELECT * FROM sales WHERE YEAR(Date) = 2013 AND MONTH(?) = 'June'
I can't merely select date ranges because different months have different number days. It would be ideal to select months by their number (ie, January being 1) or a similar approach.
How is this worked out in a mysql statement?
The fields are datetime fields such as 2012-12-01 00:00:00
Have a look at the performance and write your condition as
SELECT * FROM sales
WHERE
Date >= '2013-06-01 00:00:00'
AND
Date < '2013-07-01 00:00:00'
for the example month: June of 2013
so MySQL can use an index on the column date. You will get exactly all rows with a date in the June of 2013, even those in the first second, but not those in the first second of the July of 2013.
You see, that you don't need to know the number of days of the particular month, because you will ever use the first of both months.
You could use a bit of date calculation too:
SELECT * FROM sales
WHERE
Date >= '2013-06-01 00:00:00'
AND
Date < '2013-06-01 00:00:00' + INTERVAL 1 MONTH
so you need only to know the start and the length of the interval.
Note
The most important part of my answer is to use the column Date without using a function on this column, so MySQL can use an index.

How to check if date is in range regardless of the year

I'm wondering what would be the easiest way in MySQL to check if given date is in range regardless of the year.
In database table I have two DATE fields: start and finish stored in YYYY-mm-dd
if start = 2013-11-01 and finish = 2014-03-01 anything between 1st of November and 1st of March of any year should be accepted.
Valid dates:
2020-01-01 1980-02-28
Invalid dates:
2013-10-30 1968-07-30
There are almost certainly cleaner ways of doing it, however this should work:
((DAYOFYEAR(finish_date) > DAYOFYEAR(start_date)
AND (DAYOFYEAR(#date) >= DAYOFYEAR(start_date)
AND DAYOFYEAR(#date) <= DAYOFYEAR(finish_date)))
OR (DAYOFYEAR(finish_date) <= DAYOFYEAR(start_date)
AND (DAYOFYEAR(#date) >= DAYOFYEAR(start_date)
OR DAYOFYEAR(#date) <= DAYOFYEAR(finish_date))))
For a start date in Oct 2012 and end date in Nov 2020 this will return all dates in the Oct-Nov range. If in fact would want it to return all Dates when the range is greater than a year (and hence covers all dates of the year) you could add:
OR DATEDIFF(Day, start_date, finish_date) > 356
before the final bracket.
use DAYOFYEAR:
When the Start Date is earlier in the year than the Finished Date:
the tested Date should lye between Start Date and Finish Date (or on Start or Finish)
When the Finished Date is earlier in the year than the Start Date:
the tested Date should lye outside the Start Date and Finish Date (or on Start or Finish)
You can use some date extract function and then check your condition..
for example.
SELECT EXTRACT(MONTH FROM TIMESTAMP '2013-11-01 20:38:40');
this will give ouput start month as 11
SELECT EXTRACT(MONTH FROM TIMESTAMP '2014-03-01 20:38:40');
this will give ouput end month as 3
now you can check the condition from above two result..
SELECT * FROM tableWithDates t WHERE month(t.start) >= 11 AND month(t.finish) < 3
if you want the first of march it will go like this:
SELECT * FROM tableWithDates t WHERE month(t.start) >= 11 AND (month(t.finish) < 3 OR month(finish) <= 3 AND day(finish)<=1)
Depending on the size of the data you will run this at. You can get into performance problems, as MySQL can't use indexes of calculated columns.
If you run into this i suggest spitting the month AND/OR day into separate columns.
Edit:
Given an one parameter input as '2008-02-29'
SELECT * FROM tableWithDates t
WHERE
month(t.start) >= month('2008-02-29') AND day(t.start) >= day('2008-02-29')
AND month(t.finish) <= month('2008-02-29') AND day(t.finish) <= day('2008-02-29')

Include selected date also in date range

I am queering a data in a date range in MySQL. When I select the date range
BETWEEN '2013-01-19 00:00:00' AND '2013-01-21 00:00:00' the data is shown only 19 and 20 date but not the 21. When I write 22 over 21 then data shown from 19-21 not include 22. Now how should I write a query to include the selected date also in date range.
Eg: BETWEEN '2013-01-19 00:00:00' AND '2013-01-21 00:00:00'
Show the data from 19,20,21 Jan 2013.
Please help me
Actually it includes 2013-01-21 if and only if the recorded date and time is 2013-01-21 00:00:00. the exclusive date starts on 2013-01-21 00:00:01 and up
so to solve your problem, use 23:59:59 to include the whole time of the selected day.
BETWEEN '2013-01-19 00:00:00' AND '2013-01-21 23:59:59'
If you want to select data based only on the date, use the function DATE() to extract the date part of the data. I.e.
DATE(fieldname) BETWEEN '2013-01-19' AND '2013-01-21'