Why mysql datetime minus not correct? - mysql

This SQL.
It is very obvious that the seconds should be 86400 for one day. Why MYSQL return 1000000?
select str_to_date('2021-04-24 00:00:00', '%Y-%m-%d %H:%i:%s') - str_to_date('2021-04-23 00:00:00', '%Y-%m-%d %H:%i:%s') as seconds from dual;
+---------+
| seconds |
+---------+
| 1000000 |
+---------+

Subtracting two dates does not do what you're expecting here. What it does is format the dates as yyyyMMddHHmmss and subtract them as normal numbers, as in;
20210424000000
- 20210423000000
----------------
1000000
What you instead want is the TIMESTAMPDIFF function;
SELECT TIMESTAMPDIFF(
SECOND,
'2021-04-23 00:00:00',
'2021-04-24 00:00:00'
) AS seconds;
+---------+
| seconds |
+---------+
| 86400 |
+---------+

Because difference is
1 day
00 hours
00 minutes
00 seconds
If you try
select str_to_date('2021-05-25 00:04:05', '%Y-%m-%d %H:%i:%s') - str_to_date('2021-04-23 00:00:00', '%Y-%m-%d %H:%i:%s') as seconds;
Result is 102000405 , that means
1 month
2 days
0 hours
4 minutes
5 seconds
For seconds use UNIX_TIMESTAMP
select UNIX_TIMESTAMP('2021-04-24 00:00:00') - UNIX_TIMESTAMP('2021-04-23 00:00:00') as seconds;

Related

Select data between a given interval of time from two columns MySQL

I need to retrieve data from a table from a given interval of time. My table is like this -
id
Start Time
End Time
1
06:30:00
07:00:00
2
06:45:00
07:15:00
3
13:15:00
14:00:00
4
09:30:00
10:15:00
Given interval of time - (05:00:00 - 10:00:00)
My Expectation -
id
Start Time
End Time
1
06:30:00
07:00:00
2
06:45:00
07:15:00
4
09:30:00
10:15:00
I need to get the id (4) as its start time in the given interval of time.
So what will be the query?
so far I can imagine this -
To get all the values between the given interval of time - (05:00:00 - 10:00:00) use:
select *
from tbl
where Start_Time between '05:00:00' and '10:00:00'
or End_Time between '05:00:00' and '10:00:00';
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=ba828afe1a3ca9f21d6c104ea7dcfdff
Using comparison operator
SELECT * FROM tbl WHERE
(`start_time`>= '05:00:00' AND `start_time` <= '10:00:00') OR
(`end_time`>= '05:00:00' AND `end_time` <= '10:00:00')

MySQL date grouping select statement

I have a MySQL 8.0.23 table called events with the following schema:
eventUID - integer NOT NULL
camtimestamp - MySQL datetime stamp
direction - string - either "In" or "Out"
propUID - integer
In a single SELECT statement, I am trying to determine by hour for the last 24 hours how many cars are "In" and how many are "Out". Here is what I am trying (does not yet have the 24 hour limit built in).
select camtimestamp,count(*) from events where direction ="In" and propUID = 7 group by year(camtimestamp),month(camtimestamp),day(camtimestamp),hour(camtimestamp);
And this is a sample of what I am getting.
2022-02-14 22:02:40 38
2022-02-14 21:56:56 15
2022-02-14 20:55:30 47
2022-02-14 19:59:18 51
2022-02-14 18:59:50 36
2022-02-14 17:52:04 10
2022-02-14 16:58:01 16
2022-02-14 15:59:00 36
2022-02-14 14:58:52 44
I also have a table called datehourlist with which I can join in my SELECT.
Sample data:
2019-05-01 00:00:00
2019-05-01 01:00:00
2019-05-01 02:00:00
2019-05-01 03:00:00
2019-05-01 04:00:00
2019-05-01 05:00:00
2019-05-01 06:00:00
2019-05-01 07:00:00
2019-05-01 08:00:00
Also:
mysql> select min(datehour) from datehourlist;
+---------------------+
| min(datehour) |
+---------------------+
| 2019-05-01 00:00:00 |
+---------------------+
1 row in set (0.02 sec)
mysql> select max(datehour) from datehourlist;
+---------------------+
| max(datehour) |
+---------------------+
| 2040-12-31 00:00:00 |
+---------------------+
1 row in set (0.02 sec)
datehourlist has every hour in it from May 1, 2019 until December 31, 2040.
This is a sample of what I really want from this:
Column 1 below is a rounded grouped timestamp (vs col 1 above being a non-rounded, actual timestamp)
Column 1 below does not skip an hour if there is no data from that hour.
Column 2 below is the "In" count for that hour.
Column 3 below is the "Out" count for that hour.
2019-05-02 06:00:00 5 10
2019-05-02 07:00:00 127 10
2019-05-02 08:00:00 0 0
2019-05-02 09:00:00 115 10
2019-05-02 10:00:00 71 10
2019-05-02 11:00:00 147 10
2019-05-02 12:00:00 140 10
What SELECT statement should I use to get the output I need?
Also, how would I optimize that SELECT statement?
Within events, I have 500k events and growing by 100s everyday.
Thank you in advance for your help.
Thank you for a great solution so quickly.
SELECT dhl.datehour datehour,
COALESCE(SUM(ev.direction = 'In'), 0) `In`,
COALESCE(SUM(ev.direction = 'Out'), 0) `Out`
FROM datehourlist dhl
LEFT JOIN events ev
ON DATE_FORMAT(ev.camtimestamp, '%Y-%m-%d %H:00:00') = dhl.datehour
WHERE ev.camtimestamp >= DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00') - INTERVAL 24 HOUR
AND ev.camtimestamp < DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00')
AND ev.propUID = 7
GROUP BY dhl.datehour;
First, we need a trunc_to_hour() function that takes an arbitrary DATETIME or TIMESTAMP value and gives back the beginning of its hour. That is this.
DATE_FORMAT(camtimestamp, '%Y-%m-%d %H:00:00')
Second, we need a WHERE expression that can handle the most recent 24 hours. That is this.
WHERE camtimestamp >= DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00') - INTERVAL 24 HOUR
AND camtimestamp < DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00')
For the example timestamp 2021-03-14 16:04:30 this gives the following.
WHERE camtimestamp >= `2021-03-13 16:00:00`
AND camtimestamp < '2021-03-14 16:00:00`
That is, it chooses records for the most recent 24 complete clock hours. You may have to adjust this WHERE expression if you want the hours to date.
Third, we need conditional sums (for In and Out).
It happens that the expression direction = 'In' gives 1 when direction is In, 0 when direction is some other string (like Out), and NULL if direction itself is NULL. So
SUM(direction='In')
counts the rows meeting that criterion.
Fourth, when the SUM is null, we want to show zero. Like this.
COALESCE(SUM(direction='In'),0)
Fifth, we can put it together something like this:
SELECT DATE_FORMAT(ev.camtimestamp, '%Y-%m-%d %H:00:00') datehour,
COALESCE(SUM(ev.direction = 'In'), 0) `In`,
COALESCE(SUM(ev.direction = 'Out'), 0) `Out`
FROM events ev
WHERE ev.camtimestamp >= DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00') - INTERVAL 24 HOUR
AND ev.camtimestamp < DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00')
AND ev.propUID = 7
GROUP BY DATE_FORMAT(ev.camtimestamp, '%Y-%m-%d %H:00:00')
That gives you your result set. But it still might be missing some hours if there are no records for those hours.
So, sixth, we can join that to your pre-existing hourly calendar table like this:
SELECT dhl.datehour datehour,
COALESCE(SUM(ev.direction = 'In'), 0) `In`,
COALESCE(SUM(ev.direction = 'Out'), 0) `Out`
FROM datehourlist dhl
LEFT JOIN events ev
ON DATE_FORMAT(ev.camtimestamp, '%Y-%m-%d %H:00:00') = dhl.datehour
WHERE ev.camtimestamp >= DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00') - INTERVAL 24 HOUR
AND ev.camtimestamp < DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00')
AND ev.propUID = 7
GROUP BY dhl.datehour
And that should do it. (Not debugged.)

MYSQL select date now-1 day with TIME and between date

I want to select all rows between current day-1 with specific time 08:00am and to date now also with specific time. This is not working for example sample line code
WHERE SOME_DATE_COLUMN BETWEEN DATE_SUB(DATE(NOW() - INTERVAL 1 DAY) '08:00:00', '%Y-%m-%d %H:%i:%s') AND DATE_SUB(DATE(NOW()) '08:00:00', '%Y-%m-%d %H:%i:%s');
I tried also DATE_FORMAT
WHERE SOME_DATE_COLUMN BETWEEN DATE_FORMAT(DATE(NOW() - INTERVAL 1 DAY) '08:00:00', '%Y-%m-%d %H:%i:%s') AND DATE_FORMAT(DATE(NOW()) '08:00:00', '%Y-%m-%d %H:%i:%s');
If I run sql today I want to select all record between current date minus 1 day from 08:00am to current date 08:00am
I would do:
where
some_date_column >= current_date - interval 16 hour
and some_date_column < current_date + interval 8 hour
current_date gives you the current date (without the time part). You can then add and substract the required number of hours.
Note that this query does not use between, but instead half-open intervals. If you want consistent, adjacent segments in time, then you want to exclude one of the bounds (by convention, generally the outer bound is excluded).
Demo on DB Fiddle:
select current_date - interval 16 hour, current_date + interval 8 hour
current_date - interval 16 hour | current_date + interval 8 hour
:------------------------------ | :-----------------------------
2020-02-04 08:00:00 | 2020-02-05 08:00:00

Add and Sub time in MySQL

In MySQL table I have these value 00:00:00 and 06:00:00.
I need sub three hours on 00:00:00, return 21:00:00 and add three hours on 06:00:00, return 09:00:00.
I have tried this sql query, without success.
Please help me, thank you in advance.
mysql> SELECT
SUBTIME('00:00:00', 3),
ADDTIME('06:00:00', 3);
+------------------------+------------------------+
| SUBTIME('00:00:00', 3) | ADDTIME('06:00:00', 3) |
+------------------------+------------------------+
| -00:00:03 | 06:00:03 |
+------------------------+------------------------+
1 row in set
mysql>
#Edit 1
mysql> SELECT
'00:00:00' - INTERVAL 3 HOUR,
'06:00:00' + INTERVAL 3 HOUR;
+------------------------------+------------------------------+
| '00:00:00' - INTERVAL 3 HOUR | '06:00:00' + INTERVAL 3 HOUR |
+------------------------------+------------------------------+
| NULL | NULL |
+------------------------------+------------------------------+
1 row in set
mysql>
#Edit 2
mysql> SELECT
DATE_ADD('00:00:00', INTERVAL 3 HOUR),
DATE_ADD('06:00:00', INTERVAL 3 HOUR);
SELECT
SUBTIME('00:00:00', '03:00:00'),
ADDTIME('06:00:00', '03:00:00');
+---------------------------------------+---------------------------------------+
| DATE_ADD('00:00:00', INTERVAL 3 HOUR) | DATE_ADD('06:00:00', INTERVAL 3 HOUR) |
+---------------------------------------+---------------------------------------+
| NULL | NULL |
+---------------------------------------+---------------------------------------+
1 row in set
+---------------------------------+---------------------------------+
| SUBTIME('00:00:00', '03:00:00') | ADDTIME('06:00:00', '03:00:00') |
+---------------------------------+---------------------------------+
| -03:00:00 | 09:00:00 |
+---------------------------------+---------------------------------+
1 row in set
mysql>
Since there is actually no time like '-00:00:03', you cannot apply time operation to do such thing.
If you really need to to this, I recommend you to
Change the column to INT type, and do the operation by yourself.
Change the column to DATETIME type, and try to deal with the cross-day problem by yourself.
Or apply the following...
SELECT CONCAT(
TIMESTAMPDIFF(
HOUR,
STR_TO_DATE(CONCAT('2015/01/01 ', '00:00:00'), '%Y/%m/%d %H:%i:%s'),
STR_TO_DATE(CONCAT('2015/01/01 ', '00:00:00'), '%Y/%m/%d %H:%i:%s') - interval 3 hour
) % 24,
":",
TIMESTAMPDIFF(
MINUTE,
STR_TO_DATE(CONCAT('2015/01/01 ', '00:00:00'), '%Y/%m/%d %H:%i:%s'),
STR_TO_DATE(CONCAT('2015/01/01 ', '00:00:00'), '%Y/%m/%d %H:%i:%s') - interval 3 hour
) % 60,
":",
TIMESTAMPDIFF(
SECOND,
STR_TO_DATE(CONCAT('2015/01/01 ', '00:00:00'), '%Y/%m/%d %H:%i:%s'),
STR_TO_DATE(CONCAT('2015/01/01 ', '00:00:00'), '%Y/%m/%d %H:%i:%s') - interval 3 hour
) % 60
);
Just replace '00:00:00' and 3 hour to anything you want.
It just try to concat you time to a datetime string, and transform it into datetime then apply the interval operation. After that it apply the timediff to compute elapsed time by given unit(do not forget to % to get the correct domain). And finally concatenation the three differences.
This answer is kinda ugly, hope it is helpful to you.
It Should be
SELECT
TIME(SUBTIME(CONCAT(curdate(),' ','00:00:00'), 03:00:00)),
TIME(ADDTIME(CONCAT(curdate(),' ','00:00:00'), 03:00:00));

How do I convert time difference into a decimal weeks value in mysql?

So in my database I have 2 dates I want to get the difference between. They are in the format 2013-07-31 00:00:00. I want the different in weeks, not time. So say date 1 - date 2 = 3 days and 12 hours. I want this to be represented as a week, as in 0.5 weeks. How can I do this in my sql query?
NOTE: I want the value returned to be a decimal, e.g. 1.5 not a string
This will provide you a whole number:
SELECT TIMESTAMPDIFF(WEEK, date1, date2) AS weeks;
To include a fraction for days, use:
SELECT TIMESTAMPDIFF(DAY, date1, date2) / 7 AS weeks_days;
or a fraction for seconds, use:
SELECT TIMESTAMPDIFF(SECOND, date1, date2) / 604800 AS weeks_secs;
as 604800 is 7 * 24 * 60 * 60;
Here's an example:
SET #date1 = NOW() - INTERVAL 777 HOUR, #date2 = NOW();
SELECT
TIMESTAMPDIFF(WEEK, #date1, #date2) AS weeks,
TIMESTAMPDIFF(DAY, #date1, #date2) / 7 AS weeks_days,
TIMESTAMPDIFF(SECOND, #date1, #date2) / 604800 AS weeks_secs;
returns:
+-------+------------+------------+
| weeks | weeks_days | weeks_secs |
+-------+------------+------------+
| 4 | 4.5714 | 4.6250 |
+-------+------------+------------+