Check free time beetween times and dates with sql - mysql

Assuming that I have a table like this:
+----+----------------+------------+------------+-----------+----------+
| id | time_needed | date_start | date_stop | hour_start| hour_stop |
+----+----------------+------------+------------+-----------+----------+
| 1 | 30 | 2018-08-06 | 2018-08-06 | 08:00:00 | 08:30:00 |
| 2 | 96 | 2018-08-06 | 2018-08-06 | 10:45:00 | 14:21:00 |
| 3 | 20 | NULL | NULL | NULL | NULL |
| 4 | 56 | NULL | NULL | NULL | NULL |
+----+----------------+------------+------------+-----------+----------+
I know when I'll execute the operations 1 and 2, But instead for the 3 and 4 I just know the the time spent to execute the operations (20 and 56 minutes)
How can I check with mysql when I can execute the operation 3? I mean, is there a possibility to check when I have free time and for how long?
Looking at the table I can say that I have free time from the 08:31 to 10:44, but there is a way to check it with mysql?
EDIT
I would like to see the time free, beetween 8 am and 18 pm.

What you are demanding is not (all alone) a task of mysql. mysql can give you the DATA according to your query - but your programming language should add the logic of scheduling entries, whenever possible.
At first i would start with the following database changes:
Combine the date / hour columns into a datetime column.
remove the end_date / end_hour - you always can calcluate this with date_start + time_needed
So, you end up with a datatable like this:
+----+----------------+---------------------+
| id | time_needed | date_start |
+----+----------------+---------------------+
| 1 | 30 | 2018-08-06 08:00:00 |
| 2 | 96 | 2018-08-06 14:21:00 |
+----+----------------+---------------------+
Now, all you need to do is: Join the table with itself, and make sure everything is calculated as it should be:
-- new Task takes 25 Minutes.
SELECT DISTINCT L.* FROM time_table L LEFT JOIN time_table R
-- compare with every later schedule
on L.date_start < R.date_start
WHERE
-- use only rows that have enough time for the task that should be scheduled
(date_add(L.date_start, INTERVAL L.time_needed + 25 MINUTE ) < R.date_start
-- and only in the future
and date_add(L.date_start, INTERVAL L.time_needed MINUTE) > NOW()
-- due to the join, it might happen that we ignore entries in between.
-- make sure, there is no other task in the calculated timespan!
and not exists
(SELECT id FROM time_table x WHERE
x.date_start > L.date_start AND
x.date_Start < date_add(L.date_start, INTERVAL L.time_needed + 25 MINUTE) )
)
-- and ofc. the last row in the schedule.
OR isnull (R.date_start);
This returns both datarows, as 25 minutes can be scheduled right after every other task.
http://sqlfiddle.com/#!9/02020d8/1
14:21 - 08:00 is 6:21, and 30 minutes are "booked". So the gap is 5:51 - so a 350 Minute Task should fit after 08:00 - a 351 Minute Task not:
350 minutes to be scheduled:
http://sqlfiddle.com/#!9/02020d8/2
351 minutes to be scheduled:
http://sqlfiddle.com/#!9/02020d8/3
All you got to do afterwards:
Take the smalles id, and insert your schedule right after it. Remember, date_start will be prior_date_start + prior_time_needed.
See this example as well: Scheduling a 20 minute Task would have 3 options with the example data (Added 2 columns for your convenience):
http://sqlfiddle.com/#!9/02020d8/8

Related

How to add random interval to timestamp in MySQL?

We got the following table mytable:
+----+------------+------------+
| id | created | expired |
+----+------------+------------+
| 1 | 1496476314 | NULL |
| 6 | 1496477511 | NULL |
| 7 | 1496477518 | NULL |
| 12 | 1496477534 | NULL |
| 13 | 1496477536 | NULL |
| 15 | 1496477541 | NULL |
| 21 | 1496477548 | NULL |
| 22 | 1496477550 | NULL |
| 26 | 1496477565 | NULL |
| 28 | 1496477566 | NULL |
| 29 | 1496477583 | NULL |
+----+------------+------------+
We'd like to do the following:
set expired = created + random(15 - 30 minutes) as unix_timestamp where expired is null;
I currently have no idea to done it.
If u just can give me some ideas it would save my day.
I tried to convert the created timestamp to date_time and add to that date_time the wanted 15 - 30 minutes and finally convert the new_date_time back to unix_timestamp, but there should be an easier way.
If you want to add a random number of minutes between, say, 14 and 33, you can do it like this:
SET expired = DATE_ADD(created, INTERVAL 14 + RAND()*(33-14) MINUTE);
If you want to have seconds granularity, you need to add SECOND-typed intervals:
SET expired = DATE_ADD(created, INTERVAL 14*60 + RAND()*(33-14)*60 SECOND);
This would saves one datetime conversion if you had a DATETIME for the expired column, which makes it slightly easier to expire records (WHERE expired < NOW()). If you have an integer holding a Unix timestamp, then Darshan's answer is definitely the way to go, and you'd do well to calculate the Unix timestamp in your app and then plug it in the query:
WHERE expired <= 123456789
Having an index on that column would make expirations go blazingly fast. I think it might be even faster than the datetime method, but it's just a sensation, I haven't actually checked.
unix_timestamp is number of seconds elapsed since 1st January 1970. Now, if you want to add 15 to 30 minutes then the equivalent seconds would be 900 to 1800. Here's what you can do:
set expired = created + ROUND((RAND() * (900))+900) where expired is null;
This is how it works:
RAND() will generate a random number between 0 and 1
By using RAND() * (maximum - minimum)) + minimum we make sure we generate a number between 900 and 1800.
ROUND then rounds that number to nearest int.

SQL - select x entries within a timespan

I'm creating a database (in MySQL) with a table of measurements. For each measurement I want to store the DateTime it came in. For showing plots within an app for different intervals (measurements of the day/week/month/year) I want sample the data points I have, so I can return e. g. 30 data points for the whole year as well as for the day/hour. This is the same as done with stock price graphs:
stock price plot for 1 day
vs
stock price plot for 1 month
As you can see, the amount of data points is the same in both pictures.
So how can I select x entries within a timespan in MySQL via SQL?
My data looks like this:
+====+====================+=============+==========+
| id | datetime | temperature | humidity |
+====+====================+=============+==========+
| 1 | 1-15-2016 00:30:00 | 20 | 40 |
+----+--------------------+-------------+----------+
| 2 | 1-15-2016 00:35:00 | 19 | 41 |
+----+--------------------+-------------+----------+
| 3 | 1-15-2016 00:40:00 | 20 | 40 |
+----+--------------------+-------------+----------+
| 4 | 1-15-2016 00:45:00 | 20 | 42 |
+----+--------------------+-------------+----------+
| 5 | 1-15-2016 00:50:00 | 21 | 42 |
+----+--------------------+-------------+----------+
| 6 | 1-15-2016 00:55:00 | 20 | 43 |
+----+--------------------+-------------+----------+
| 7 | 1-15-2016 01:00:00 | 21 | 43 |
+====+====================+=============+==========+
Let's say, I always want two data points (in reality a lot more). So for the last half hour I want the database to return data point 1 and 4, for the last ten minutes I want it to return 6 and 7.
Thanks for helping!
PS: I'm sorry for any errors in my English
OK, assuming a very simple systematic approach, you can get the first and last entry for any defined period:
select *
from table
where mydatetime =
(select
max(mydatetime)
from table
where mydatetime between '2017-03-01' and '2017-03-15'
)
OR mydatetime =
(select
min(mydatetime)
from table
where mydatetime between '2017-03-01' and '2017-03-15'
)
I believe your answer can be found at the following location:
https://stackoverflow.com/a/1891796/7176046
If you are looking to filter out any items not within your date/time your query would use:
Select * from table where Date/Time is (What you want to sort by)

How to get the expired candidates in MySQL

I am having a table with the columns for expired_date and registered_date.
Expired date have set for 2 days to registered date.
Its look like this:
+--------------+--------------+---------------------+
| candidate_id | date_expires | date_added |
+--------------+--------------+---------------------+
| 1 | 2016-03-26 | 2016-03-24 14:42:18 |
| 2 | 2016-03-23 | 2016-03-21 15:43:40 |
| 3 | 2016-02-15 | 2016-02-13 14:53:30 |
| 4 | 2016-02-22 | 2016-02-20 14:54:19 |
+--------------+--------------+---------------------+
My question is, I want to select expired profile to current date and time.
This is how I tried it, but it doesn't work.
SELECT * FROM candidates WHERE date_added = DATE_ADD(date_added, INTERVAL 2 DAY);
Hope somebody may help me out.
Thank you.
You may try any of the following query which meets your need.
SELECT
*
FROM candidates
WHERE date_expires < CURDATE();
Or if you want to get the expired accounts with respect to date_added field then follow the query given below:
SELECT
*
FROM candidates
WHERE DATE_ADD(date_added, INTERVAL 2 DAY) < CURDATE();
EDIT:
For fine-grained comparison you may use the following query:
SELECT
*
FROM candidates
WHERE TIMESTAMPADD(DAY,2,date_added) < NOW();
Note: Actually you don't need to store the expired dates in database. Rather you can store the profile life time (in this case it is 2 Days) in database if this profile life time varies across different accounts. You don't need to store this in database if it's constant in nature (i.e. Always 2 DAYS).
So if you want to bring this change in your table structure then it would look like below:
+--------------+--------------+---------------------+
| candidate_id | days | date_added |
+--------------+--------------+---------------------+
| 1 | 2 | 2016-03-24 14:42:18 |
| 2 | 5 | 2016-03-21 15:43:40 |
| 3 | 3 | 2016-02-13 14:53:30 |
| 4 | 10 | 2016-02-20 14:54:19 |
+--------------+--------------+---------------------+
You need a modified query for this change.
Here it is:
SELECT
*
FROM candidates
WHERE TIMESTAMPADD(DAY,days,date_added) < NOW();
You're looking for this
SELECT *
FROM candidates
WHERE date_expires < NOW();

How to generalize a sequential COUNT() of chronological data without loops or cursors?

I have read all the arguments: Tell SQL what you want, not how to get it. Use set-based approaches instead of procedural logic. Avoid cursors and loops at all costs.
Unfortunately, I have been racking my brain for weeks and I can't figure out how to come up with a set-based approach to generating an iterative COUNT for sequential subsets of chronologically ordered data.
Here is the specific application of the problem I am working on.
I do football-related research using a database that comprises many years of play-by-play data, which is of course arranged chronologically by year, game, and play. The database is loaded onto a web server running MySQL 5.0.
The fields I need for this particular problem are contained in the core table. Here is some sample data from the relevant part of the table:
GID | PID | OFF | DEF | QTR | MIN | SEC | PTSO | PTSD
--------------------------------------------------------
121 | 2455 | ARI | CHI | 2 | 4 | 30 | 17 | 10
121 | 2456 | ARI | CHI | 2 | 4 | 15 | 17 | 10
121 | 2457 | ARI | CHI | 2 | 3 | 53 | 17 | 10
121 | 2458 | ARI | CHI | 2 | 3 | 31 | 20 | 10
The columns represent, respectively: unique game identifier, unique play identifier, which team is on offense for that play, which team is on defense for that play, the quarter and time the play occurred, and the offense's and defense's scores going into the play. In other words, in (hypothetical) game 121, the Arizona Cardinals scored a field goal on play 2457 (i.e., going into play 2458).
What I want to do is go through several years' worth of data game by game, second by second, and count the number of times any possible score differential occurred at any given elapsed time. The following query arranges the data by seconds elapsed and score differential:
SELECT core.GID, core.PID, core.QTR, core.MIN, core.SEC, core.PTSO, core.PTSD,
((core.QTR - 1) * 900 + (900-(core.MIN * 60 + core.SEC))) AS secEl,
core.PTSO - core.PTSD AS oDif, (core.PTSO - core.PTSD) * -1 AS dDif
FROM core
ORDER BY secEl ASC, oDif ASC;
The result looks something like this:
GID | PID | OFF | DEF | QTR | MIN | SEC | PTSO | PTSD | secEl | oDif | dDif
---------------------------------------------------------------------------------
616 | 100022 | CHI | MIN | 1 | 15 | 00 | 0 | 0 | 0 | 0 | 0
617 | 100169 | HOU | DAL | 1 | 15 | 00 | 0 | 0 | 0 | 0 | 0
618 | 100224 | PHI | SEA | 1 | 15 | 00 | 0 | 0 | 0 | 0 | 0
619 | 100303 | JAX | NYJ | 1 | 15 | 00 | 0 | 0 | 0 | 0 | 0
Although that looks pretty, my goal is not to sort the data chronologically. Rather, I want to step sequentially through every one of the 4,500 possible seconds (four 15-minute quarters plus one 15-minute overtime period) in an NFL game and count the number of times every score differential has ever occurred in each one of those seconds.
In other words, I don't want to count just the number of times a team has been up by, say, 21 points at 1,800 seconds elapsed (i.e., the start of the second quarter) between 2002 and 2013. I want to count the number of times a team has been up by 21 points at any point in a game. On top of that, I want to do this for every score differential that has ever occurred (i.e., -50, -49, -48, ..., 0, 1, 2, ... 48, 49, 50, ...) for every second of every game.
This would be relatively easy to accomplish with a series of nested loops, but it wouldn't be the most reusable of code.
What I want to do is construct set logic that will COUNT the instances of each score differential that has occurred at every second of time elapsed without using loops or cursors. The results would be tabulated as follows:
secondsElapsed | scoreDif | Occurrences
-----------------------------------------
10 | -1 | 12
10 | 0 | 125517
10 | 1 | 0
10 | 2 | 3
Here is a sample query for getting the total number of instances of a specific score differential (+21) at a specific time point (3,000 seconds elapsed):
SELECT ((core.QTR - 1) * 900 + (900-(core.MIN * 60 + core.SEC))) AS timeElapsed,
(core.PTSO - core.PTSD) AS diff, COUNT(core.PTSO - core.PTSD) AS occurrences
FROM core
WHERE ((core.QTR - 1) * 900 + (900-(core.MIN * 60 + core.SEC))) = 3000
AND ABS(core.PTSO - core.PTSD) = 21
That query returns the following results:
timeElapsed | diff | occurrences
----------------------------------
3000 | 21 | 5
Now I want generalize this query to count the instances of every differential at every second elapsed.
Your description is rather confusing but if you want to "COUNT all of the possible score differentials for every possible second without using loops or cursors" then I would do something like:
1) Build a work table (either a temporary table# or a Table data type#) and fill it with the time increments you want e.g.
QTR | MIN | SEC |
1 | 00 | 01
1 | 00 | 02
..
1 | 01 | 59
1 | 02 | 00
1 | 02 | 01
1 | 02 | 02
..
4 | 15 | 59
2) You then use this as the basis of your query. Cross Join a list of the games you are interested in with the work table to give you a table of every game and every minute in that game.
3) With the result of (2) left join your query above back into it?
With this result set you can then look at a whole game and sum\count as neccessary without having to loop.
Not sure if this will cure your problem, but you could try using row_number over a partition...
SELECT ROW_NUMBER() OVER (PARTITION BY <column> ORDER BY <column>) AS aColumn, aColumn FROM aTable
I did it using a sub-query and two variables to define the time point and another to define the point difference.
The query then returns the Diff, then the amount of times the offensive side had it, followed by the defensive side and total times.
SET #Diff INT = 7;
SET #Seconds INT = 1530;
SELECT ABS(core.PTSO - core.PTSD) AS diff, SUM(CASE WHEN core.PTSO - core.PTSD <= 0 THEN 1 ELSE 0 END) OffensiveTimes, SUM(CASE WHEN core.PTSO - core.PTSD >= 0 THEN 1 ELSE 0 END) DefensiveTimes, SUM(1) TotalTimes
FROM (SELECT core.GID, core.PID, core.QTR, core.MIN, core.SEC, core.PTSO, core.PTSD,
((core.QTR - 1) * 900 + (900-(core.MIN * 60 + core.SEC))) AS secEl,
core.PTSO - core.PTSD AS oDif, (core.PTSO - core.PTSD) * -1 AS dDif
FROM core
) core
WHERE secEl = #Seconds AND ABS(core.PTSO - core.PTSD) = #Diff
GROUP BY ABS(core.PTSO - core.PTSD);
This returns this for the small dataset you gave
7 diff, 0 OffensiveTimes, 1 DefensiveTimes, 1 Times
Hope that was what you were looking for :)

MYSQL check the value of the next row

I have a table 'mytable' like this
ID | dateTime | data |
------------------------------------------
1 | 2013-09-01 00:15:00 | some data |
2 | 2013-09-01 00:15:00 | some data |
4 | 2013-09-01 00:15:00 | some data |
5 | 2013-09-01 00:30:00 | some data |
6 | 2013-09-01 00:30:00 | some data |
7 | 2013-09-01 00:30:00 | some data |
8 | 2013-09-01 00:45:00 | some data |
9 | 2013-09-01 00:45:00 | some data |
10 | 2013-09-01 00:45:00 | some data |
I was fine before but I accidentally changed the dateTime to round to 15 minutes (I was supposed to round it for 5 minutes) please refere to this, No I want to round the time for 5 minutes.
I think the only way I can do this, is to get the dateTime of one record then check the record in the next row, if both are same then add 5 minutes into it.
How do I get the value of the next row and compare it with previous one?
Can anyone help me with this??
Thanks
This query will output the new datetime values, where I add 5 minutes every time the datetime is the same as the previous row, ordered by Id:
SELECT ID,
DATE_ADD(dateTime, INTERVAL 5 * (ID -
(SELECT MIN(ID) FROM MyTable T2 WHERE T2.dateTime = T1.dateTime)
) MINUTE) AS dateTime,
data
)
FROM MyTable T1
It works by adding 5 times the difference in ID values between the current row and the first row (minimum ID) of the same dateTime value.
While this will definitely do what you want, depending on how you rounded down to 15 minutes, the output will not necessarily be the same as if you had rounded down to 5 minutes from your original data. Your best option would be to restore from a backup.