Mysql hourly average with intervals starting on the half hour - mysql

I have a mysql database with which contains data in 5 minute bins. I'd like to create hourly average of the data starting on the half hour.
By using mysql built-in group by:
select date,AVG(AE) from mytable group by date(date),HOUR(date);
would compute average value from say, 01:00 to 02:00. Instead I would like hourly averages to be computed from 00:30 to 01:30, were the value would then be the hourly average at 01:00.
This query fail when a new day starts:
select date, AVG(AE) from mytable group by date(date), HOUR( date ) + FLOOR( MINUTE( date ) / 30 );
+---------------------+------------------+
| date | AVG(AE) |
+---------------------+------------------+
| 1997-01-01 22:30:00 | 23 |
| 1997-01-01 23:30:00 | 28.3 |
| 1997-01-02 00:00:00 | 20.1333333333333 |
| 1997-01-02 00:30:00 | 29.3 |
| 1997-01-02 01:30:00 | 27.5666666666667 |
| 1997-01-02 02:30:00 | 43.4166666666667 |
which is the closest I've gotten :-)
In another post ( https://stackoverflow.com/a/6560742/1142735 ) it was suggested that GROUP BY FLOOR(MOD((mytimestamp-1800)/3600)) would create intervals starting on the half hour if timestamp was used. I am using datetime.
Thanks
Paul

Anything that uses the DATE() function will fail to correctly group the interval 23:30 - 00:30.
Use:
FLOOR((UNIX_TIMESTAMP(date) - 1800) / 3600)

Related

How to get the number of days in period?

Storage table
| id| product_id | date_add | date_remove
------------------------------------------------------------------
| 1 | 10 |2018-04-02 08:28:43 | 2018-04-03 07:21:08
| 2 | 10 |2018-04-05 08:28:43 | 2018-04-06 08:28:50
| 3 | 10 |2018-04-01 08:28:43 | 2018-04-05 08:28:50
| 4 | 12 |2018-04-01 08:28:43 | 2018-04-03 07:21:08
| 5 | 12 |2018-04-04 08:28:43 | 2018-04-04 10:28:43
| 6 | 13 |2018-03-01 08:28:43 | 2018-03-01 10:28:43
how to find ?
how many days product was in the storage in period 2018-04-01 to 2018-04-05?
find result
| product_id | days
| 10 | 5
| 12 | 3
try
SELECT product_id, SUM(DATEDIFF(date_remove, date_add)) as days
FROM storage
where date_remove BETWEEN '2018-04-01 00:00:00'
AND '2018-04-05 23:59:59'
AND date_add BETWEEN '2018-04-01 00:00:00'
AND '2018-04-05 23:59:59'
GROUP BY product_id
but result wrong because 'SUM' sums all days
get result
| product_id | days
| 10 | 7
correct result
| product_id | days
| 10 | 5
upd
http://rextester.com/QFS96125
result 9,646805555556 but probably maximum 5 days and product_id 13 correct 0,436608796296 but result 0,87
First you want to look at all date ranges that are within or overlap with the range 2018-04-01 to 2018-04-05.
where date_add < date '2018-04-06' and date_remove >= date '2018-04-01'
Then, with the ranges found, you want to consider only their days in the range 2018-04-01 to 2018-04-05.
greatest(date_add, date '2018-04-01')
least(date_remove, date '2018-04-06')
Then you want to count days. Here you need a rule. Do you want to look at single ranges and only take their full days which you add up then? Or do you want to consider day fractions, add all up and see how many full days result? For the latter you could get durations in seconds and add these up:
select
product_id,
sum(timestampdiff(second, greatest(date_add, date '2018-04-01'),
least(date_remove, date '2018-04-06'))
) / 60 / 60 / 24 as days
from storage
where date_add < date '2018-04-06' and date_remove >= date '2018-04-01'
group by product_id
order by product_id;
This gets you
product_id | days
-----------+---------------
10 | 5,599872685185
12 | 2,036400462963
Feel free to use FLOOR, CEIL or ROUND on the resulting days.
Rextester demo: http://rextester.com/XTVU47656
To obtain such result, try
SELECT SUM(DATEDIFF(date_remove, date_add)) as days
FROM table
GROUP BY product_id
Keep in mind that this will sum all the days for the same product_id. To get the result for each id, use:
SELECT id, product_id, DATEDIFF(date_remove, date_add) as days
FROM table

Mysql query difference between time fields has 24 hours

how i can check time difference between two time fields,having 24 hours
consider my table "tb1",that has following fields id,startTime,endTime
we need find out sum of time difference between(startTime,endTime) has 24 hours with add number min as total records.that means if total difference 14.44 minutes.total count records is 4,we need add four minutes to total hours
Below query i have tired:
Sample data
Select id,StartTime, EndTime from tablename;
+----+-----------+----------+
| id | StartTime | EndTime |
+----+-----------+----------+
| 40 | 00:00:00 | 02:59:00 |
| 41 | 04:00:00 | 05:59:00 |
| 42 | 06:00:00 | 13:29:00 |
| 43 | 15:00:00 | 18:29:00 |
+----+-----------+----------+
Select Sum(TIMESTAMPDIFF(EndTime, StartTime)) + 4 mintues from tablename;
Desired output:
12(in hours)
Thanks in advance
Assuming that you always add the number of records as minutes
SELECT SEC_TO_TIME((SUM(TIMESTAMPDIFF(MINUTE, StartTime, EndTime)) + COUNT(*)) * 60)
FROM tablename;
With your data this will return H:M:S
16:00:00
http://sqlfiddle.com/#!9/953c0c/21
SELECT round(sum((time_to_sec(timediff(EndTime,StartTime))/3600)+(4/60)))
FROM TABLE
limit 1;

Select all records that were created on a given day N months ago

Given a table orders:
+-----+---------+-------------------------+
| id | price | created_at |
+-----+---------+-------------------------+
| 1 | 16.50 | 2017-02-28 12:52:00.824 |
| 2 | 22.00 | 2017-10-03 15:12:39.107 |
| 3 | 50.00 | 2017-12-03 12:54:42.658 |
| 4 | 12.00 | 2018-01-02 07:21:47.808 |
| . | . | . |
| . | . | . |
| . | . | . |
+-----+---------+-------------------------+
and current date:
+---------------------+
| NOW() |
+---------------------+
| 2018-01-03 10:33:14 |
+---------------------+
I'd like to select all records that were created on current day any months ago. So for above data my query should return:
+-----+---------+-------------------------+
| id | price | created_at |
+-----+---------+-------------------------+
| 2 | 22.00 | 2017-10-03 15:12:39.107 |
| 3 | 50.00 | 2017-12-03 12:54:42.658 |
+-----+---------+-------------------------+
But there are some edge cases for the last day of month:
if it's 31-days month, it's trivial
if it's 30-days month, the query should return all records created on 30th and 31st day of month
if it's February in a leap year, the query should return all records created on 29th, 30th and 31st day of month
if it's February in a normal year, the query should return all records created on 28th, 29th, 30th and 31st day of month
What I have tried is something like this:
SELECT * FROM orders
JOIN (
SELECT id, PERIOD_DIFF(
DATE_FORMAT(NOW(), "%Y%m"),
DATE_FORMAT(created_at, "%Y%m")
) AS diff
FROM orders
) AS periods
ON orders.id = periods.id
WHERE DATEDIFF(created_at + INTERVAL diff MONTH, NOW()) = 0;
But it doesn't cover the edge cases and I believe there is a smarter way (maybe without a subquery) to achieve the expected results.
EDIT:
To give you more context - what I need is a kind of a loop. I have a cron job scheduled to run once a day at midnight. This job should select all ids of orders that were created on this day any months ago and then refresh some other data associated with those ids. The important part is to refresh this data exactly once every month - that's why the last day of months is so crucial.
For example, given following creation dates:
DATES = [
2015-05-30, 2016-02-29, 2016-10-03,
2016-12-31, 2017-05-28, 2018-01-03
]
+---------------+------------------------------------+
| NOW() | SHOULD BE INCLUDED |
+---------------+------------------------------------+
| 2018-01-03 | 2016-10-03, 2018-01-03 |
| 2018-02-28 | 2016-02-29, 2016-12-31, 2017-05-28 |
| 2018-04-30 | 2015-05-30, 2016-12-31 |
| 2018-10-31 | 2016-12-31 |
+---------------+------------------------------------+
Can I suggest a slight simplification Walerian?
SELECT
*
FROM
orders
WHERE
(
DAYOFMONTH(created_at) = DAYOFMONTH( NOW() ) --monthdays that match
)
OR
(
( DAYOFMONTH( LAST_DAY( NOW() ) ) = DAYOFMONTH( NOW() ) ) --base date is end of month
AND
( DAYOFMONTH(created_at) > DAYOFMONTH( NOW() ) ) --target monthdays are beyond base monthday
)
Incidentally I don't have a MySQL environment, so I'm just taking it on trust that these are the correct functions in MySQL.
Use DAYOFMONTH() function to compare the day of the NOW() and the created_at.
Like this:
SELECT * FROM ORDERS
WHERE (DAYOFMONTH(NOW() < LAST_DAY(NOW()) -- if not last day of month
AND DAYOFMONTH(created_at) = DAYOFMONTH(NOW())
OR (LAST_DAY(NOW()) = DAYOFMONTH(NOW()) -- if last day of month
AND DAYOFMONTH(NOW()) BETWEEN DAYOFMONTH(created_at) AND LAST_DAY(created_at)) --
Inspired by suresubs's answer, I figured out how the query should look like.
SELECT * FROM orders
-- (1)
WHERE (DAYOFMONTH(NOW) < DAYOFMONTH(LAST_DAY(NOW()))
AND DAYOFMONTH(created_at) = DAYOFMONTH(NOW()))
-- (2)
OR (DAYOFMONTH(LAST_DAY(NOW())) = DAYOFMONTH(NOW())
AND DAYOFMONTH(created_at) BETWEEN DAYOFMONTH(NOW()) AND DAYOFMONTH(LAST_DAY(created_at)));
It's using DAYOFMONTH() and LAST_DAY() functions and it's divided into two cases:
Today is not the last day of current month.
Today is the last day of current month.

how to retrieve date from db without seconds

+---------+---------------------+
| user_id | registration_date |
+---------+---------------------+
| 6988 | 2017-07-24 12:10:29 |
| 6985 | 2017-07-23 12:10:00 |
| 6980 | 2017-07-22 11:10:40 |
| 6979 | 2017-07-21 02:30:00 |
| 6978 | 2017-07-20 08:10:15 |
| 6977 | 2017-07-19 12:10:29 |
| 6976 | 2017-07-18 12:10:00 |
| 6975 | 2017-07-17 05:10:02 |
| 6974 | 2017-07-16 06:10:11 |
| 6951 | 2017-07-15 09:10:50 |
+---------+---------------------+
select registration_date from users WHERE registration_date BETWEEN '2017-07-24 12:10' - INTERVAL 10 DAY AND '2017-07-24 12:10';
I am having this data in my sql table and i am trying to get the data between 2017-07-24 12:10 and INTERVAL 10 DAY AND '2017-07-24 12:10'(excluding seconds).
Now i want to get this | 6988 | 2017-07-24 12:10:29 | ...Means i want to ignore the seconds value from the data that is stored in the db and then get the data.so that the desired data with user_id 6988 will come.
select registration_date from users WHERE registration_date BETWEEN '2017-07-24 12:10' - INTERVAL 10 DAY AND '2017-07-24 12:10';
I am trying this...But not working .
Add the min and max value for seconds. In start add the 00 and for the range end 59 as seconds
select registration_date from users
WHERE registration_date BETWEEN '2017-07-24 12:10:00' - INTERVAL 10 DAY
AND '2017-07-24 12:10:59';
For MySQL, you can use DATE and STR_TO_DATE functions to extract/compare dates, e.g.:
SELECT DATE_FORMAT(registration_date, '%Y-%m-%d %H:%i')
FROM users
WHERE registration_date BETWEEN DATE_ADD(STR_TO_DATE('2017-07-24 12:10', '%Y-%m-%d %H:%i') - INTERVAL 10 DAY)
AND STR_TO_DATE('2017-07-24 12:10', '%Y-%m-%d %H:%i');
Here's the documentation.
You can use DATE_FORMAT to get the parts of the date that you want, and compare this.
Since you want a range of dates, you need to test that separately from the time.
WHERE DATE(registration_date) BETWEEN '2017-07-14' AND '2017-07-24'
AND DATE_FORMAT(registration_date, '%H:%i') = '12:10'

Get sales per hour

I want to get the number of sales per hour in a specific date:
table : invoices
+-------+-----------+-----------+--------------------------+
| id | name | amout | date |
+-------+-----------+-----------+--------------------------+
| 1 | John | 12313 | 2017-05-20 13:50:08 |
| 2 | Mary | 5335 | 2017-05-17 22:21:35 |
| 3 | Jeff | 23 | 2017-05-17 22:32:13 |
| 4 | Bill | 132 | 2017-05-17 23:25:55 |
| 5 | Bob | 853 | 2017-05-17 24:52:37 |
+-------+-----------+-----------+--------------------------+
So, I want to get this output:
9 a.m. to 10 a.m. we generated X invoices.
10 a.m. to 11 a.m. we generated Y invoices.
11 a.m. to 12 a.m. we generated Z invoices.
X,Y and Z it's the number of invoices generated in these interval.
How I can do that? I use MySQL.
Thanks!
Three SQL concepts will help you get an answer to this question.
"Truncating" a datestamp; that is, extracting the hour from it. For example, 2017-05-27 14:37.20 is truncated to 2017-05-27 14:00:00.
Selecting rows from your table with datestamps on a particular day.
Using COUNT(*) and GROUP BY.
You can truncate like this.
SELECT DATE_FORMAT(`date`, '%y-%m-%d %H:00:00') hour_starting
FROM invoices
You can add to that query to select rows for a particular date like this
SELECT DATE_FORMAT(`date`, '%y-%m-%d %H:00:00') hour_starting
FROM invoices
WHERE `date` >= '2017-05-27`
AND `date` < '2017-05-27' + INTERVAL 1 DAY
Notice that this chooses all rows with date values on or after (>=) midnight on 2017-05-27. and before but not including (<) midnight on the next day.
Finally, you can use COUNT like this.
SELECT DATE_FORMAT(`date`, '%y-%m-%d %H:00:00') hour_starting,
COUNT(*) invoice_count
FROM invoices
WHERE `date` >= '2017-05-27`
AND `date` < '2017-05-27' + INTERVAL 1 DAY
GROUP BY DATE_FORMAT(`date`, '%y-%m-%d %H:00:00')