Sum datetime in MySQL rows - php

Question:
Is it possible to group all rows in MySQL and sum the hours?
Starttime - type:datetime, Stoptime - type:datetime
Data
Starttime, stoptime
2016-10-25 09:00:00, 2016-10-29 17:00:00
2016-11-26 09:00:00, 2016-11-26 17:00:00
2016-11-30 09:00:00, 2016-11-30 17:00:00
2017-01-28 09:00:00, 2017-01-28 17:45:00
The code below sums all the hours between 2016-10-25 and 2017-01-28. I need it to sum all the time on every row and then all rows together. Is it possible to sum this in MySQl or am I bound to PHP?
SELECT
MIN(starttime),
MAX(stoptime),
SUM(TIME_TO_SEC(TIMEDIFF(stoptime, starttime))/3600) AS total_hours
FROM mytable WHERE id = 1219

To sum up all differences, you don't need min(starttime) or max(stoptime), just use sum of timestampdiff, e.g.
select sum(timestampdiff(hour, starttime, stoptime))
from mytable
If you want fractional hours, keep time_to_sec(...) / 3600 as in your question
select sum(time_to_sec(timediff(stoptime, starttime)) / 3600)
from mytable
See also sqlfiddle

Related

How to SELECT a date between two dates

How can I select from mysql with php a range between 2 dates?
The working day, start for example, at 7:00 am of 2022-01-01 and ends at 2:00 am of 2022-01-02. I want that all collected datas from 00:00 to 2:00 am of 2022-01-02 are grouped inside previous date.
Now I use this query
SELECT date_format(dateAdded,"%m-%d") as mth,COUNT(productID) as total, productID FROM statisticsNW WHERE userID = "35" AND productID = "1193'" AND YEAR(dateAdded) = "2022" AND month(dateAdded) = "01" GROUP by year(dateAdded),month(dateAdded), day(dateAdded) ORDER by year(dateAdded),month(dateAdded)
and the result is this but the "total" is wrong because is from 00:00 to 23:59 of the same day. The correct query the I want is from 7:00 to 6:59 of the next day. But from 00:00 to 6:59 datas must be counted in the previous day.
you can add 5 hours to the start_time and end_time, so the it appears the shift starts at midnight
select DATEDIFF(HH,cast('2022-01-24 19:00:00' as datetime),cast('2022-01-25 00:00:00' as datetime)) as time_5_hrs
select dateadd(HOUR,5,cast('2022-01-02 19:00:00' as datetime)) as starttime, dateadd(HOUR,5,cast('2022-01-03 02:00:00' as datetime)) as endtime,datediff(HH,dateadd(HOUR,5,cast('2022-01-02 19:00:00' as datetime)),dateadd(HOUR,5,cast('2022-01-03 02:00:00' as datetime))) diff
By doing this you can get both date are the same and you will be able to group it as single day.
I have solved
SELECT DATE_SUB(DATE_ADD("2017-06-15 5:30:00", INTERVAL 24 HOUR), INTERVAL 1 MINUTE);

How to make single array in between dates

I have one table called task
id t_title t_started_on t_due_on
1 Test 1 2018-01-18 01:00 PM 2018-01-20 01:00 PM
2 Test 2 2018-01-25 01:00 PM 2018-01-27 01:00 PM
from here i have to select dates like first row start date is 2018-01-18 01:00 PM (t_started_on) and end date is 2018-01-20 01:00 PM(t_due_on).total is 3 days
2018-01-18
2018-01-19
2018-01-20
same as second row also 3 days
2018-01-25
2018-01-26
2018-01-27
Expected Result
Array
(
[allocatedDate] => 2018-01-18
[allocatedDate] => 2018-01-19
[allocatedDate] => 2018-01-20
[allocatedDate] => 2018-01-25
[allocatedDate] => 2018-01-26
[allocatedDate] => 2018-01-27
)
How to write a select query in above case?
Like I said in your previous question, you should not store your dates as strings, but in date datatype: that will make your data less error prone and your queries simpler. Now you'll have to convert those strings to dates each time you need to do date/time calculations with them.
To generate the dates inside periods, you need a helper table, which can be useful also for many other purposes: a table with one column that has natural numbers starting from 0 up to some large n. You could create it like this:
create table nums (i int);
insert into nums values (0), (1), (2), (3);
insert into nums select i+4 from nums;
insert into nums select i+8 from nums;
insert into nums select i+16 from nums;
insert into nums select i+32 from nums;
insert into nums select i+64 from nums;
insert into nums select i+128 from nums;
insert into nums select i+256 from nums;
You can see how you double the number of records by adding a similar insert statement, but this will already generate 512 records, which would be more than enough for your purposes: it should have the highest number of days that a period can have in your tasks table.
Then you can use this query to get the desired output:
SELECT DISTINCT date_add(d_started_on, interval i day)
FROM (
SELECT date(STR_TO_DATE(t_started_on, '%Y-%m-%d')) as d_started_on,
datediff(
date(STR_TO_DATE(t_due_on, '%Y-%m-%d')),
date(STR_TO_DATE(t_started_on, '%Y-%m-%d'))
) as days
FROM tasks
) as base
INNER JOIN nums ON i <= days
ORDER BY 1
See also SQLfiddle

Get count of several times slots on between given two mysql time slots within datetime field

I have several in data and out date mysql datetime values. I need to return total count from given dateperiod and given time slot
Ex.
time
2012-02-01 10:00
2012-02-01 12:00
2012-02-01 14:00
2012-02-02 09:00
2012-02-02 10:00
2012-02-03 11:00
how to get data basis on time and date slot form datetime field as in this question i only want to get data from date 2012-02-01 to 2012-02-02 and time from 09:00 to 12:00 hence this should not provide the data of 2012-02-01 14:00 hope you got this now
you need only to add count(*) in your statement.
SELECT count(*) FROM users WHERE created_at BETWEEN '2012-02-01 09:00' AND '2012-02-02 12:00'
Try this -
SELECT count(*) as c FROM users WHERE created_at
BETWEEN '2012-02-01 09:00' AND '2012-02-02 02:00' AND
Time(c) BETWEEN '09:00' AND '02:00'
2012-02-01 14:00 is rightfully included in the result of your query, what you want to achieve can be done this way
SELECT * FROM users WHERE
(DATE(created_at) BETWEEN '2012-02-01' AND '2012-02-02')
AND
(TIME(created_at) BETWEEN '09:00' AND '12:00')
You have a typo in your query. The closing time is 14:00, not 12:00:
SELECT COUNT(*)
FROM users
WHERE created_at BETWEEN '2012-02-01 09:00' AND '2012-02-02 14:00' ;
EDIT:
If you are trying to limit the times and dates separately, then use two conditions:
SELECT COUNT(*)
FROM users
WHERE created_at >= '2012-02-01' AND created_at < '2012-02-03' AND
time(created_at) BETWEEN '09:00:00' AND '14:00:00' ;

Difference between two date and print seconds of each day by using mysql and php

I a have table in mysql with some data like this:
id from to
---- -------------------- ---------------------------
1 2013-01-31 23:50:00 2013-02-02 09:00:00
2 2013-02-05 11:21:12 2013-02-08 01:01:01
3 2013-02-08 17:33:44 2013-02-08 18:22:55
4 2013-02-12 01:40:12 2013-02-12 02:00:59
5 2013-02-28 01:40:12 2013-03-02 02:00:59
I need a Mysql query or a php code for finding difference between 'from' column and 'to' column of each rows, and find how many seconds are there in each day between 'from' and 'to' date separately, for example for row 1 the needed output be something like this:
difference between 2013-01-31 23:50:00 - 2013-02-02 09:00:00 for row 1
2013-01-31 : 600 sec (24:00:00 - 23:50:00 => 600 sec)
2013-02-01 : 86400 sec (24:00:00 - 00:00:00 => 86400 sec)
2013-02-02 : 32400 sec (09:00:00 - 00:00:00 => 32400 sec)
and so on ... for each row
MySQL command is preferred. which code can create this output? is there any specific function in php or mysql for creating this output?
I read these answers:
mysql calculate seconds between two date/times for each day
MySQL: how to get the difference between two timestamps in seconds
but these are not my answer.
for information:
link 1 is a question like my question but the answer is not true because "The command needs grouped by day" but how?!
and the second is not my question but question one marked as duplicated with link 2 and it is not true.
Let me assume that you have a table of dates. If so, you can use a join or correlated subquery:
select d.date,
(select sum(timestampdiff(second,
greatest(d.date, t.from),
least(d.date, t.to)
))
from table t
where t.to >= d.date and
t.from < date_add(d.date, interval 1 day)
) as NumSeconds
from dates d;
If you don't have a dates table of some sort, you can create one on the fly:
from (select date('2013-01-31') as date union all
select date('2013-02-01') union all
. . .
) dates

Creating hour groups for time series data MySQL

I have a MySQL database with data recorded every 15 minutes. For simplicity, lets assume there are 2 fields:
DATETIME Created
Double Value
I would like to draw a chart which needs for each hour the opening, min, max, and closing values for an hour. To do this I need to return results from my MySQL query to my PHP to create a JSON. I would like to do this in the MySQL query so that the response is cached.
Here is an example of the problem, given 9 data points trying to get 2 hour groups:
Creation Value
2014-03-25 12:15:00 413.17011
2014-03-25 12:00:00 414
2014-03-25 11:45:00 415
2014-03-25 11:30:00 415
2014-03-25 11:15:00 415.5
2014-03-25 11:00:00 415.5
2014-03-25 10:45:00 416
2014-03-25 10:30:00 416
2014-03-25 10:15:00 415.99
I would need:
Hour 1 (11:15:00 to 12:15:00)
Open: 415.5
Close: 413.17011
High: 415.5
Low: 413.17011
Hour 2 (10:15:00 to 11:15:00)
Open: 415.99
Close: 415.5
High: 416
Low: 415.5
Of course for the full 24 hours this would need repeating, this is just an example.
Any help is really appreciated!
Here is the current MySQL dump for the example (Using MySQL version 2.6.4-pl3):
--
-- Table structure for table `exampleTable`
--
CREATE TABLE `exampleTable` (
`created` datetime NOT NULL,
`value` double NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
--
-- Dumping data for table `exampleTable`
--
INSERT INTO `exampleTable` VALUES ('2014-03-25 12:15:00', 413.17011);
INSERT INTO `exampleTable` VALUES ('2014-03-25 12:00:00', 414);
INSERT INTO `exampleTable` VALUES ('2014-03-25 11:45:00', 415);
INSERT INTO `exampleTable` VALUES ('2014-03-25 11:30:00', 415);
INSERT INTO `exampleTable` VALUES ('2014-03-25 11:15:00', 415.5);
INSERT INTO `exampleTable` VALUES ('2014-03-25 11:00:00', 415.5);
INSERT INTO `exampleTable` VALUES ('2014-03-25 10:45:00', 416);
INSERT INTO `exampleTable` VALUES ('2014-03-25 10:30:00', 416);
INSERT INTO `exampleTable` VALUES ('2014-03-25 10:15:00', 415.99);
Get it to work
You might try
SELECT
DATE(created) AS day,
HOUR(created) AS hour,
(
SELECT Value FROM `table` AS b
WHERE DATE(a.created) = DATE(b.created)
AND HOUR(a.created) = HOUR(b.created)
ORDER BY created ASC LIMIT 1
) AS Open,
(
SELECT Value FROM `table` AS b
WHERE DATE(a.created) = DATE(b.created)
AND HOUR(a.created) = HOUR(b.created)
ORDER BY created DESC LIMIT 1
) AS Close,
MIN(value) AS Low,
MAX(value) AS High
FROM `table` AS a
GROUP BY DATE(created), HOUR(created)
this groups all your rows by DATE+HOUR and computes the MIN respectively MAX as Low or High. To find the first and last row for Open and Close, the easiest in SQL syntax is a subselect. It selects all rows which are relevant for the current row, and sorts them ascending or descending. Then selects the first row.
Please consider that this groups only by hour. Instead of
Hour 1 (11:15:00 to 12:15:00)
Hour 2 (10:15:00 to 11:15:00)
this groups like
Hour 1 (11:00:00 to 11:59:00)
Hour 2 (10:00:00 to 10:59:00)
If you want to keep the 15 minutes offset, you may subtract this from your created timestamp (created - INTERVAL 15 MINUTE) at all occurrences of created in the sql query above.
I created a working sqlfiddle for you.
Performance
Just as hint: If you can, you might want to split date and time into two columns (of types date and time). This way you do not need to cast DATE() on created everytime, but can use the new date column instead. You can then add a combined index to this new columns too, which speeds up your query. See this sqlfiddle for an example.
To get your grouping right, you can use
FLOOR(( UNIX_TIMESTAMP(myTable.dateCreated) - 900 ) / 3600)
where 3600 sets the interval at 1 hour and the - 900 sets the offset at 00:15
Since you need the MIN() and MAX for each of your four values, you'll need to JOIN the main table to itself but grouped by the min or max (based on the column).
finally, you have each sub-query (joined table) calculate the grouping hour above so you can use that to join them. Here's what I cam up with (with slightly different column names and
SELECT openDate,Open,Close,High,Low
FROM (SELECT FLOOR(( UNIX_TIMESTAMP(myTable.dateCreated) - 900 ) / 3600)
AS
theHour,
myTable.value AS Open,myTable.dateCreated openDate
FROM myTable
JOIN (SELECT value,MIN(dateCreated) AS dateCreated
FROM myTable
GROUP BY FLOOR(( UNIX_TIMESTAMP(dateCreated) - 900 )
/ 3600)
) AS
aggTable
ON aggTable.dateCreated = myTable.dateCreated) AS
openTable
LEFT JOIN (SELECT FLOOR(( UNIX_TIMESTAMP(myTable.dateCreated) - 900
) /
3600) AS
theHour
,
myTable.value AS Close,myTable.dateCreated closeDate
FROM myTable
JOIN (SELECT value,MAX(dateCreated) AS dateCreated
FROM myTable
GROUP BY FLOOR(( UNIX_TIMESTAMP(dateCreated) - 900 ) / 3600)
) AS
aggTable
ON aggTable.dateCreated = myTable.dateCreated) AS closeTable
ON openTable.theHour = closeTable.theHour
LEFT JOIN (SELECT
FLOOR((
UNIX_TIMESTAMP(myTable.dateCreated) - 900 ) / 3600) AS
theHour,
MAX(
value)
AS High
FROM myTable
GROUP BY theHour) AS highTable
ON closeTable.theHour = highTable.theHour
LEFT JOIN (SELECT
FLOOR((
UNIX_TIMESTAMP(myTable.dateCreated) - 900 ) / 3600) AS
theHour,
MIN(
value)
AS Low
FROM myTable
GROUP BY theHour) AS lowTable
ON highTable.theHour = lowTable.theHour

Categories