MySQL - Select rows where 1 hour before datetime column - mysql

I have these rows
id | start_time |
1 | 2018-06-15 02:00:00 |
2 | 2018-06-15 02:45:00 |
3 | 2018-06-15 03:45:00 |
I want to select rows that are 1 hour before the start_time. So if the time is 2018-06-15 01:00:00 then the first row should be returned.
How do i do this? I've tried below but i don't know how to subtract 1 hour from start_time.
SELECT *
FROM table1
WHERE DATE_FORMAT(start_time, '%Y-%m-%d %H') <= DATE_FORMAT(NOW(), '%Y-%m-%d %H');

To subtract hours ,use date_sub function
In your case
SELECT DATE_SUB(DATE_FORMAT(start_time, '%Y-%m-%d %H'), INTERVAL 1 HOUR)

Related

how may i select the time interval from last month ?, and it must also be between 1pm from last day of the last month till midday of the actual day

I've been trying to solve this problem for a few hours , so far what i have reached is something like this:
SELECT * FROM mytable WHERE DATE(datetime_column)
BETWEEN DATE_SUB(DATE_FORMAT(NOW(),'%Y-%M-01'),INTERVAL 1 DAY) AND NOW()
AND HOUR(datetime_column) > = '13'
ORDER BY
datetime_column
Besides the day interval, i also need the hour interval which must be between 13h pm from last day of the last month till midday for present date.
The fiddle doesnt seem to work with the current query but its working in my database, but check fiddle for more info:
https://www.db-fiddle.com/f/a3jui7aPMevU81Cka4BqXg/0
And sample data:
CREATE TABLE mytable (
id INT,
datetime_column DATETIME
);
INSERT INTO mytable (id,datetime_column) VALUES
(1,'2020-03-31 08:00:00'),
(2,'2020-03-31 13:00:00'),
(3,'2020-04-02 14:30:00'),
(4,'2020-04-06 18:00:00'),
(5,'2020-04-21 05:00:00'),
(6,'2020-04-23 13:00:00'),
(7,'2020-04-23 14:00:00');
If more info is necessary please let me know.
I think this what you want
SELECT * FROM mytable
WHERE (
DATE(datetime_column) > LAST_DAY(CURDATE() - INTERVAL 1 MONTH)
AND datetime_column < (CURDATE() + INTERVAL 12 HOUR)
)
OR (
DATE(datetime_column) = LAST_DAY(CURDATE() - INTERVAL 1 MONTH)
AND HOUR(datetime_column) >= 13
);
+------+---------------------+
| id | datetime_column |
+------+---------------------+
| 2 | 2020-03-31 13:00:00 |
| 3 | 2020-04-02 14:30:00 |
| 4 | 2020-04-06 18:00:00 |
| 5 | 2020-04-21 05:00:00 |
+------+---------------------+
2 rows in set (0.00 sec)
Here LAST_DAY(CURDATE() - INTERVAL 1 MONTH) gives the last day of previous month.
And datetime_column < (CURDATE() + INTERVAL 12 HOUR) tests if that time is before mid day of today.

Count all records in last 12 hours on hourly basis in mysql

I want to count records hourly in last 12 hours from my mysql table.
I found this link but my problem is, let say currently it's January 7 2016, 9 AM then i would like to count records from 7th Jan 9AM to Jan 6th 9PM.
My table structure is as following:
Table name :: cebod_cdr
id|userid|starting_date|total_duration
1 | 17 | 2016-01-07 09:00:00 | 12
2 | 17 | 2016-01-07 07:30:24 | 45
3 | 17 | 2016-01-07 01:12:21 | 5
4 | 17 | 2016-01-06 10:30:00 | 18
5 | 17 | 2016-01-06 10:45:00 | 25
Example output
hour | calls
9AM | 1
8AM | 0
7AM | 1
6AM | 0
5AM | 0
4AM | 0
3AM | 0
2AM | 0
1AM | 1
12AM | 0
11PM | 0
10PM | 2
If there is any problem in displaying hours in desired format(1-12), i can display it in some other format like 24 hours format etc.
SELECT HOUR(starting_date) AS Hour, COUNT(*) AS calls
FROM cebod_cdr
WHERE starting_date > DATE_ADD(NOW(), INTERVAL -12 HOUR)
GROUP BY HOUR(starting_date)
I have found the answer as below:
SELECT za_hours.za_hour as hour, COUNT(id) as calls
FROM (
SELECT NOW() - INTERVAL 1 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 2 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 3 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 4 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 5 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 6 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 7 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 8 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 9 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 10 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 11 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 12 HOUR as za_hour )
za_hours
LEFT JOIN
cebod_cdr
ON DATE_FORMAT(za_hours.za_hour, '%Y-%m-%d %H:') = DATE_FORMAT(starting_date, '%Y-%m-%d %H:')
AND starting_date >= NOW() - INTERVAL 12 HOUR
GROUP BY za_hours.za_hour
ORDER BY za_hours.za_hour
Please suggest if i can improve this query.
Try this:
SELECT
date_format(dh.starting_date, '%Y-%m-%d %H:%i:%s') as hour,
COUNT(md.id) AS count
FROM
cebod_cdr dh
LEFT JOIN cebod_cdr md ON dh.starting_date = DATE_FORMAT(md.starting_date, '%Y-%m-%d %H:00:00')
WHERE dh.starting_date >= DATE_SUB(NOW(),INTERVAL 12 HOUR)
AND dh.starting_date < NOW()
GROUP BY dh.starting_date
ORDER BY dh.starting_date

finding a specific date in MySql

I knew this will give syntax error.
SELECT DATE_SUB(DATE_SUB(now(),INTERVAL 3 MONTH)),INTERVAL EXTRACT(DAY FROM (DATE_SUB(now(),INTERVAL 3 MONTH))) DAY) as oldDate
I am new to SQL and in here I am trying to find 3 month old date and the first day of that month.
for example 3 month old date from today will be 28-11-2014 so I have to show 01-11-2014.
so how to sort above code to avoid syntax error.
You can use DATE_FORMAT to format the date according to your requirements.
SELECT DATE_SUB(NOW(), INTERVAL 3 MONTH) 3months_ago,
DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 3 MONTH), "01-%m-%Y") first_day
FROM DUAL
+---------------------+------------+
| 3months_ago | first_day |
+---------------------+------------+
| 2014-11-28 09:20:50 | 01-11-2014 |
+---------------------+------------+
You can use date_format() function along with date_sub() to get the 1st day of month
mysql> select date_format(date_sub(curdate(),interval 3 month),'01-%m-%Y') ;
+--------------------------------------------------------------+
| date_format(date_sub(curdate(),interval 3 month),'01-%m-%Y') |
+--------------------------------------------------------------+
| 01-11-2014 |
+--------------------------------------------------------------+

MySQL - make a weekly report that includes starting day (twist: week starting wednesday)

I have this kind of table with time based data:
| entity_id | ttime | value |
-------------------------------------------
| 1 | 2014-11-01 00:00:04 | 553 |
| 1 | ... | 600 |
| 2 | ... | 234 |
I want to get the average of the value grouped by week and entity_id. But I would like also the starting day of the week to appear in the results. Additional complexity is that the week starts on wednesday.
I can group by YEAR(ttime + INTERVAL 3 DAY), WEEK(ttime + INTERVAL 3 DAY) but is it possible to print the first day of the group (wednesday) in the results?
Thanks
maybe something like this:
SELECT
`entity_id`,
DATE_SUB(ttime, INTERVAL WEEKDAY(ttime)-2 DAY),
SUM(`value`)
FROM `table`
GROUP BY `entity_id`, YEARWEEK(ttime + INTERVAL 4 DAY)
SqlFiddle
I found this solution:
SELECT
str_to_date(CONCAT(YEAR(ttime + INTERVAL -3 DAY),
WEEK(ttime + INTERVAL -3 DAY), 'Wednesday'), '%X%V %W') as WeekCommencing,
entity_id, AVG(value),
FROM `table`
GROUP BY WeekCommencing, entity_id

Grouping MySQL datetime into intervals irrespective of timezone

This question has been asked before but I am facing a slightly different problem.
I have a table which logs events and stores their timestamps (as datetime). I need to be able to break up time into chunks and get number of events that occurred in that interval. The interval can be custom (Say from 5 minutes to 1 hour and even beyond).
The obvious solution is to convert the datetime to unix_timestamp divide it by number of seconds in the interval, take its floor function and multiply it back by the number of seconds. Finally convert the unix_timestamp back to the datetime format.
This works fine for small intervals.
select
from_unixtime(floor(unix_timestamp(event.timestamp)/300)*300) as start_time,
count(*) as total
from event
where timestamp>='2012-08-03 00:00:00'
group by start_time;
This gives the correct output
+---------------------+-------+
| start_time | total |
+---------------------+-------+
| 2012-08-03 00:00:00 | 11 |
| 2012-08-03 00:05:00 | 4 |
| 2012-08-03 00:10:00 | 4 |
| 2012-08-03 00:15:00 | 7 |
| 2012-08-03 00:20:00 | 8 |
| 2012-08-03 00:25:00 | 1 |
| 2012-08-03 00:30:00 | 1 |
| 2012-08-03 00:35:00 | 3 |
| 2012-08-03 00:40:00 | 3 |
| 2012-08-03 00:45:00 | 5 |
~~~~~OUTPUT SNIPPED~~~~~~~~~~~~
But if I increase the interval to say 1 hour (3600 sec)
mysql> select from_unixtime(floor(unix_timestamp(event.timestamp)/3600)*3600) as start_time, count(*) as total from event where timestamp>='2012-08-03 00:00:00' group by start_time;
+---------------------+-------+
| start_time | total |
+---------------------+-------+
| 2012-08-02 23:30:00 | 35 |
| 2012-08-03 00:30:00 | 30 |
| 2012-08-03 01:30:00 | 12 |
| 2012-08-03 02:30:00 | 18 |
| 2012-08-03 03:30:00 | 12 |
| 2012-08-03 04:30:00 | 4 |
| 2012-08-03 05:30:00 | 3 |
| 2012-08-03 06:30:00 | 13 |
| 2012-08-03 07:30:00 | 269 |
| 2012-08-03 08:30:00 | 681 |
| 2012-08-03 09:30:00 | 1523 |
| 2012-08-03 10:30:00 | 911 |
+---------------------+-------+
The reason, as far as I could gauge, for the boundaries not being set properly is that unix_timestamp will convert time from my local timezone (GMT + 0530) to UTC and then output the numerical value.
So a value like 2012-08-03 00:00:00 will actually be 2012-08-02 18:30:00. Dividing and using floor will set the minutes part to 00. But when I use from_unixtime, it will convert it back to GMT + 0530 and hence give me intervals that begin at 30 mins.
How do I ensure the query works correctly irrespective of the timezone? I use MySQL 5.1.52 so to_seconds() is not available
EDIT:
The query should also fire correctly irrespective of the interval (can be hours, minutes, days). A generic solution would be appreciated
You can use TIMESTAMPDIFF to group by intervals of time:
For a specified interval of hours, you can use:
SELECT '2012-08-03 00:00:00' +
INTERVAL FLOOR(TIMESTAMPDIFF(HOUR, '2012-08-03 00:00:00', timestamp) / <n>) * <n> HOUR AS start_time,
COUNT(*) AS total
FROM event
WHERE timestamp >= '2012-08-03 00:00:00'
GROUP BY start_time
Replace the occurances of 2012-08-03 00:00:00 with your minimum input date.
<n> is your specified interval in hours (every 2 hours, 3 hours, etc.), and you can do the same for minutes:
SELECT '2012-08-03 00:00:00' +
INTERVAL FLOOR(TIMESTAMPDIFF(MINUTE, '2012-08-03 00:00:00', timestamp) / <n>) * <n> MINUTE AS start_time,
COUNT(*) AS total
FROM event
WHERE timestamp >= '2012-08-03 00:00:00'
GROUP BY start_time
Where <n> is your specified interval in minutes (every 45 minutes, 90 minutes, etc).
Be sure you're passing in your minimum input date (in this example 2012-08-03 00:00:00) as the second parameter to TIMESTAMPDIFF.
EDIT: If you don't want to worry about which interval unit to pick in the TIMESTAMPDIFF function, then of course just do the interval by seconds (300 = 5 minutes, 3600 = 1 hour, 7200 = 2 hours, etc.)
SELECT '2012-08-03 00:00:00' +
INTERVAL FLOOR(TIMESTAMPDIFF(SECOND, '2012-08-03 00:00:00', timestamp) / <n>) * <n> SECOND AS start_time,
COUNT(*) AS total
FROM event
WHERE timestamp >= '2012-08-03 00:00:00'
GROUP BY start_time
EDIT2: To address your comment pertaining to reducing the number of areas in the statement where you have to pass in your minimum parameter date, you can use:
SELECT b.mindate +
INTERVAL FLOOR(TIMESTAMPDIFF(SECOND, b.mindate, timestamp) / <n>) * <n> SECOND AS start_time,
COUNT(*) AS total
FROM event
JOIN (SELECT '2012-08-03 00:00:00' AS mindate) b ON timestamp >= b.mindate
GROUP BY start_time
And simply pass in your minimum datetime parameter once into the join subselect.
You can even make a second column in the join subselect for your seconds interval (e.g. 3600) and name the column something like secinterval... then change the <n>'s to b.secinterval, so you only have to pass in your minimum date parameter AND interval one time each.
SQLFiddle Demo
the easier method would be:
Method1
select date(timestamp) as date_timestamp, hour(timestamp) as hour_timestamp, count(*) as total
from event
where timestamp>='2012-08-03 00:00:00'
group by date_timestamp, hour_timestamp
if you would like to use your original approach.
Method2
select from_unixtime(floor(unix_timestamp(event.timestamp-1800)/3600)*3600+1800) as start_time,
count(*) as total
from event
where timestamp>='2012-08-03 00:00:00'
group by start_time;
EDIT1
for the first method, it also allows user to set different interval.
For example, if user wants the log to group by 15 minutes,
select date(time) as date_timestamp,
hour(time) as hour_timestamp,
floor(minute(time) as minute_timestamp / 15) * 15 as minute_timestamp
count(*) as total
from event
group by date_timestamp, hour_timestamp, minute_timestamp