Please try the following...
SET @workingScheduleTime := ( SELECT DATE_ADD( '2017-05-06 22:00:59', INTERVAL -20 MINUTE ) );
UPDATE TableName
JOIN ( SELECT product_id,
CASE
WHEN TIME( DATE_ADD( @workingScheduleTime, INTERVAL 20 MINUTE ) ) NOT BETWEEN '05:00:01' and '22:29:59' THEN
@workingScheduleTime := DATE_ADD( TIMESTAMP( DATE( @workingScheduleTime ), '05:00:01' ), INTERVAL 1 DAY )
ELSE
@workingScheduleTime := DATE_ADD( @workingScheduleTime, INTERVAL 20 MINUTE )
END AS ScheduleTime
FROM TableName
) AS redatedList ON TableName.product_id = redatedList.product_id
SET TableName.ScheduleTime = redatedList.ScheduleTime;
This solution by works by looping through each record and adding 20
minutes
to the value given to the previous record's ScheduleTime
field. It also allows the initial value of ScheduleTime
to be specified. Thus we will need to start with a working value of ScheduleTime
that is 20
minutes
before our initial value so that the first iteration of the loop will return our initial value. Thus my solution starts with the statement...
SET @workingScheduleTime := ( SELECT DATE_ADD( '2017-05-06 22:00:59', INTERVAL -20 MINUTE ) );
With our working value thus initialised I have implemented an UPDATE
of the table TableName
using a SELECT
statement based upon Eric
's solution found at MySQL - UPDATE query based on SELECT Query. The statement follows...
UPDATE TableName
JOIN ( SELECT product_id,
CASE
WHEN TIME( DATE_ADD( @workingScheduleTime, INTERVAL 20 MINUTE ) ) NOT BETWEEN '05:00:01' and '22:29:59' THEN
@workingScheduleTime := DATE_ADD( TIMESTAMP( DATE( @workingScheduleTime ), '05:00:01' ), INTERVAL 1 DAY )
ELSE
@workingScheduleTime := DATE_ADD( @workingScheduleTime, INTERVAL 20 MINUTE )
END AS ScheduleTime
FROM TableName
) AS redatedList ON TableName.product_id = redatedList.product_id
SET TableName.ScheduleTime = redatedList.ScheduleTime;
This statement starts by performing an INNER JOIN
between one instance of TableName
to the results of the following subquery based on their shared value of product_id
...
SELECT product_id,
CASE
WHEN TIME( DATE_ADD( @workingScheduleTime, INTERVAL 20 MINUTE ) ) NOT BETWEEN '05:00:01' and '22:29:59' THEN
@workingScheduleTime := DATE_ADD( TIMESTAMP( DATE( @workingScheduleTime ), '05:00:01' ), INTERVAL 1 DAY )
ELSE
@workingScheduleTime := DATE_ADD( @workingScheduleTime, INTERVAL 20 MINUTE )
END AS ScheduleTime
FROM TableName
This subquery selects the value of product_id
for each record in TableName
and then checks if the next value of the working value will occur within a timeframe prohibited by the Questioner as being too late / too early. If it does then the next acceptable time (05:00:01
on the next day) is chosen by the CASE
statement. If the nominee value falls within the acceptable timeframe then it is chosen by the CASE
statement. The working value is updated
The value chosen by the CASE
statement is then chosen as the subquery's new value of ScheduleTime
.
As mentioned above the results of the subquery are then joined to TableName
in such way that each existing record of TableName
effectively has it's new value appended to it. The SET
statement uses this newly established relationship to change each existing value of ScheduleTime
to its corresponding new value.
This answer was tested against a dataset created using the CREATE
statement from the Question and populated using the following script...
INSERT INTO TableName ( product_id,
ScheduleTime )
VALUES ( '01', '2017-05-07 22:00:59' ),
( '02', '2017-05-07 09:09:59' ),
( '03', '2017-05-07 09:59:59' ),
( '04', '2017-05-07 09:49:59' ),
( '05', '2017-05-07 23:09:59' ),
( '06', '2017-05-07 23:09:59' ),
( '07', '2017-05-07 23:09:59' ),
( '08', '2017-05-07 23:09:59' ),
( '09', '2017-05-07 23:09:59' ),
( '10', '2017-05-07 23:09:59' ),
( '11', '2017-05-07 23:09:59' ),
( '12', '2017-05-07 23:09:59' ),
( '13', '2017-05-07 23:09:59' ),
( '14', '2017-05-07 23:09:59' ),
( '15', '2017-05-07 23:09:59' ),
( '16', '2017-05-07 23:09:59' ),
( '17', '2017-05-07 23:09:59' ),
( '18', '2017-05-07 23:09:59' ),
( '19', '2017-05-07 23:09:59' ),
( '20', '2017-05-07 23:09:59' );
The results of my code have been confirmed as appropriate by the Questioner.
Further Reading
https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#operator_between (on MySQL's BETWEEN
and NOT BETWEEN
operators)
https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date (on MySQL's DATE()
function)
https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-add (on MySQL's DATE_ADD()
function)
https://dev.mysql.com/doc/refman/5.7/en/set-statement.html (on MySQL's SET
statement)
https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_time (on MySQL's TIME()
function)
https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timestamp (on MySQL's TIMESTAMP()
function)
https://dev.mysql.com/doc/refman/5.7/en/update.html (on MySQL's UPDATE
statement)