get average interarrival time for service requests by timestamp - mysql

I have partly the following MySQL schema
ServiceRequests
----------
id int
RequestDateTime datetime
This is what a typical collection of records might look like.
1 | 2009-10-11 14:34:22
2 | 2009-10-11 14:34:56
3 | 2009-10-11 14:35:01
In this case the average request time is (34+5)/2 = 19.5 seconds, being
14:34:22 ---> (34 seconds) ----> 14:34:56 ------> (5 seconds) -----> 14:35:01
Basically I need to work out the difference in time between consecutive records, sum that up and divide by the number of records.
The closest thing I can think of is to convert the timestamp to epoch time and start there. I can add a field to the table to precalculate the epoch time if necessary.
How do I determine 19.5 using a sql statement(s)?

You don't really need to know the time difference of each record to get the average. You have x data points ranging from some point t0 to t1. Notice that the the last time - first time is also 39 sec. (max-min)/(count-1) should work for you
select max(RequestDateTime)-min(RequestDateTime) / (count(id)-1) from ServiceRequests;
Note: This will not work if the table is empty, due to a divide by zero.
Note2: Different databases handle subtraction of dates differently so you may need to turn that difference into seconds.
Hint: maybe using TIMEDIFF(expr1,expr2) and/or TIME_TO_SEC(expr3)

Related

Date table lookup efficiency - MySQL

I need to calculate the number of "working minutes" between two datetime values, lets call them 'Created' and 'Finished'.
'Finished' is always subsequent to 'Created'. The two values can differ by anything from 1 second to several years. The median difference is 50,000 seconds or roughly 14 hours.
Working minutes are defined as those occurring between 0900 to 1700 hours, Monday to Friday; excluding weekends and official holidays in our country.
I decided a lookup table was the way to go, so I generated a table of all work minutes, explicitly excluding weekends, nights and holidays...
CREATE TABLE `work_minutes` (
`min` datetime NOT NULL,
PRIMARY KEY (`min`),
UNIQUE KEY `min_UNIQUE` (`min`)
)
I populated this programatically with all the "working minutes" between years 2017 to 2024, and at this point I started to get the feeling I was being very inefficient as the table began to balloon to several hundred thousand rows.
I can do a lookup easily enough, for instance:
SELECT COUNT(min) FROM `work_minutes` AS wm
WHERE wm.min > '2022-01-04 00:04:03'
AND wm.min <= '2022-02-03 14:13:09';
#Returns 10394 'working minutes' in 0.078 sec
This is good enough for a one-off lookup but to query a table of 70,000 value pairs takes over 90 minutes.
So, I am uncomfortable with the slowness of the query and the sense that the lookup table is unnecessarily bloated.
I am thinking I need to set up two tables, one just for dates and another just for minutes, but not sure how to implement. Date logic has never been my forte. The most important thing to me is that the lookup can query over 70,000 values reasonably quickly and efficiently.
Working in MySQL 5.7.30. Thanks in advance for your expertise.
Divide the timerange to 3 parts - starting and finishing incomplete day parts, and middle part which consists from a lot of complete days. Of course if both starting and finishing time stamps have the same date part then it will be one part only, if their dates are consecutive then you\ll have 2 parts to process.
There is no problem to calculate the number of working minutes in incomplete day part. Common overlapping formula with weekday checking will help.
Create static calendar/service table which starts from the date which is earlier than any possible date in your beginning timestamp with guarantee and includes all dates after any possible date in your finishing timestamp. Calculate cumulative working minutes for each date in the table. This table allows to calculate the amount of working time in any range of complete days with single substraction.
Plan A: Convert the DATETIME values to seconds (from some arbitrary time) via TO_SECONDS(), then manipulate them with simple arithmetic.
Plan B: Use the DATEDIFF() function.
Your COUNT(min) counts the number of rows where min IS NOT NULL. You may as well say COUNT(*). But did you really want to count the number of rows?

MySQL Limit amount of records returned between 2 dates

I'm afraid I with this situation:
I have a MySQL table with just 3 columns: ID, CREATED, TOTAL_VALUE.
A new TOTAL_VALUE is recorded roughly every 60 seconds, so about 1440 times a day.
I am using PHP to generate some CanvasJS code that plots the MySQL records into line graph - this so that I can see how TOTAL_VALUE changes over time.
it works great for displaying 1 day worth of data, but when doing 1 week(7*1440=10080 plot points) things get really slow.
And a date range of for example 1-JAN-2016 and 1-SEP-2016 just leads to time outs in the PHP script.
How can I write some MySQL that still selects records between a date range but limit the rows returned to ie max 1000 rows?
I need to optimize this by limiting the number of data points that need to be plotted.
Can MySQL do some clever stuff where it decides to skip 1 every so many rows and return 1000 averaged values - this so that my line graph would by approximation still be correct- but using fewer data points?

How to add extra 5 minutes in mysql using query

I'm new for mysql, Already value in time field, I want to update extra 5 minutes in time field using query. I tried so many things but not working.
Here my query:
UPDATE STUDENT SET START_TIME = ADDTIME(START_TIME, 500) WHERE ID = 1;
Above query working but one issue is there that is, If my field having 23:55:00.
I want result after executing query 00:00:00 but it updates 24:00:00.
Anyone help me!
Thanks in advance!!
This is bit tricky, because you only have the time, and you want it to wrap around to 0 after hitting 24 hours. My approach is to extract the number of seconds from START_DATE, add 5 minutes, then take the mod of this by 24 hours to wrap around to zero if it exceeds one day's worth of seconds.
UPDATE STUDENT
SET START_TIME = CAST(STR_TO_DATE(CAST(MOD((TIME_TO_SEC(START_TIME) + 300), 86400) AS CHAR(5)), '%s') AS TIME)
WHERE ID = 1
In the demo below, you can see the logic in action which correctly converts 23:55:00 with five minutes added to become 00:00:00.
SQLFiddle
However, the easiest solution in your case might be to just use a DATETIME and ignore the date component. Then the time should wrap automatically to a new day.
select addtime('23:55:00', '00:06:00');
output - 24:01:00 (Ideally it is right, because time datatype represents only time, if it converts to 00:01:00 then time component looses 24hr, which is wrong)
select addtime('2016-09-01 23:55:00', '00:06:00');
output - 2016-09-02 00:01:00 (In this case, 24hr gets added in date so time component is represented as 00:01:00)
If the requirement is to get it as 00:01:00 then here is the workaround -
SELECT TIME((ADDTIME(TIME('23:59:59'), TIME('02:00:00')))%(TIME('24:00:00')));
reference -
ADDTIME() return 24 hour time

Whats the best way to store a time duration in a MySQL larger than the TIME range?

I'm in need of a method to store a time duration in a db field. I'm building a website where customers should be able to choose how long they would like an advert to display from a particular start date.
I had thought about using TIME but that has a max of '838:59:59' which works out at about 34 days. Its possible that a client would want an advert to exist for longer than that.
So what would be the best way to deal with this? Just a really large INT?
If you intend to have a column for start time and one for duration, I think you can store it in seconds. So, I assume you will have something like this;
+-----------+--------------------------+------------------+
| advert_id | start_time | duration_seconds |
+-----------+--------------------------+------------------+
| 2342342 |'2012-11-12 10:23:03' | 86400 |
+-----------+--------------------------+------------------+
(For the sake of the example, we will call this table adverts)
advert_id - a key pointing to your advert
start_time - the time the advert should start (data type - TIMESTAMP)
duration_seconds - Time in seconds that the advert is supposed to "live" (INTEGER(11)
SELECT TIME_TO_SEC(timediff(now(),start_time)) as 'time_difference_in_seconds_since_advert_started' FROM adverts;
If you want to get only adverts that have not expired, you will run a query like this;
SELECT * FROM `adverts` WHERE TIME_TO_SEC(timediff(now(),start_time))<=`duration_seconds`;
That's one way I would do it if I were to go with the "duration" field.
Yes, you can store time as INT data type (or another big integer: MEDIUMINT, LONGINT). Then use you can easily get days and time part from this, e.g. -
SELECT time DIV 86400 AS days, SEC_TO_TIME(column1 MOD 86400) AS time FROM table
Where 86400 is a number of seconds in 24h (60 * 60 * 24 = 86400).
not the best solution but you can add one column in your db, and check when time is more than 24 hours, calculate it as 1 day and write in that column, and all the rest time write in time column. But selecting from db you should calculate also that column of days

Returning rows of aggregate results from single SQL query

I have a MySQL table containing a column to store time and another to store a value associated with that time.
time | value
------------
1 | 0.5
3 | 1.0
4 | 1.5
.... | .....
The events are not periodic, i.e., the time values do not increment by fix interval.
As there are large number of rows (> 100000), for the purpose of showing the values in a graph I would like to be able to aggregate (mean) the values for an interval of fixed size over the entire length of time for which the data is available. So basically the output should consist of pairs of interval and mean values.
Currently, I am splitting the total time interval into fixed chunks of time, executing individual aggregate queries for that interval and collecting the results in application code (Java). Is there a way to do all of these steps in SQL. Also, I am currently using MySQL but am open to other databases that might support an efficient solution.
SELECT FLOOR(time / x) AS Inter, AVG(value) AS Mean
FROM `table`
GROUP BY Inter;
Where x is your interval of fixed size.
I've usually solved this through a "period" table, with all the valid times in it, and an association with the period on which I report.
For instance:
time day week month year
1 1 1 1 2001
2 1 1 1 2001
....
999 7 52 12 2010
You can then join your time to the "period" table time, and use AVG.