sql - добавление временного интервала с пропуском определенного периода - PullRequest
5 голосов
/ 11 ноября 2010

У меня есть запрос mySql, который добавляет определенный интервал времени в поле datetime.

UPDATE table T 
   SET T.ending = DATE_ADD(T.ending, INTERVAL T.hours * 3600 * some_other_variable_factors SECONDS)) 

Теперь мне нужно определить, находится ли новое время окончания между несколькими часами (скажем, с 20:00 до 06:00), что следует исключить из расчета.

Т.е..если старое окончание - сегодня, 19:58, и мы добавляем 4 минуты, то новое окончание должно быть завтра, 06: 02

Дополнительная сложность заключается в том, что количество времени для добавления может быть больше 24 часов. Так, если старое окончание сегодня, 19.00, и мы добавляем 24 часа, новое окончание должно быть послезавтра, 15.00 (что звучит как название действительно плохого фильма;)

Есть ли способ добиться этого в MySQL?В одном запросе?Я также думал о хранимых процедурах, но у меня нет никакого опыта.

Некоторые данные испытаний:

   CREATE TABLE IF NOT EXISTS `tt` (
      `source` datetime NOT NULL,
      `hours` int(11) NOT NULL,
      `off_start` int(11) NOT NULL,
      `off_long` int(11) NOT NULL,
      `correct` datetime NOT NULL    
    ) ENGINE=InnoDb;


    INSERT INTO `tt` (`source`, `hours`, `off_start`, `off_long`, `correct`) VALUES
    ('2010-11-11 12:00:00', 1, 20, 10, '2010-11-11 13:00:00'),
    ('2010-11-11 19:00:00', 1, 20, 10, '2010-11-12 06:00:00'),
    ('2010-11-11 19:00:00', 2, 20, 10, '2010-11-12 07:00:00'),
    ('2010-11-11 19:00:00', 3, 20, 10, '2010-11-12 08:00:00'),
    ('2010-11-11 19:00:00', 24, 20, 10, '2010-11-13 15:00:00'),
    ('2010-11-11 19:00:00', 48, 20, 10, '2010-11-15 11:00:00'),
    ('2010-11-11 19:00:00', 72, 20, 10, '2010-11-17 07:00:00');

Ответы [ 3 ]

3 голосов
/ 11 ноября 2010
SELECT  CASE
        WHEN HOUR((t_ending + INTERVAL some_other_variable_factors HOUR)  - INTERVAL 20 HOUR) < 10 THEN
                t_ending + INTERVAL some_other_variable_factors HOUR + INTERVAL 10 HOUR
        ELSE
                t_ending + INTERVAL some_other_variable_factors HOUR
        END
FROM    mytable

INTERVAL 20 HOUR означает, что ваше время отключения начинается с 20:00, INTERVAL 10 HOUR означает, что оно длится 10 часов (20:00 до 06:00). Отрегулируйте соответственно.

Обновление:

SET @hours = 54;

SELECT  CAST('2010-01-01 15:00:00' + INTERVAL @hours HOUR AS DATETIME);

--
2010-01-03 21:00:00


SELECT  CASE
        WHEN HOUR(CAST('2010-01-01 15:00:00' + INTERVAL @hours HOUR AS DATETIME)  - INTERVAL 20 HOUR) < 10 THEN
                CAST('2010-01-01 15:00:00' + INTERVAL @hours HOUR + INTERVAL 10 HOUR AS DATETIME)
        ELSE
                CAST('2010-01-01 15:00:00' + INTERVAL @hours HOUR AS DATETIME)
        END;

--
2010-01-04 07:00:00
2 голосов
/ 16 ноября 2010

Было немного сложно в одном запросе, но этот запрос должен работать:

--------------
SELECT source, correct, hours_to_end, (source + INTERVAL hours_to_end HOUR) ending
FROM (
    SELECT source, correct
        , LEAST(hours, hours_to_off)
          + (((hours_left - MOD(hours_left, on_long)) / on_long) * 24
          + off_long
          + MOD(hours_left, on_long)) * overlap hours_to_end
    FROM (
        SELECT source, correct, hours, on_long, off_long, hours_to_off
            , GREATEST(0, hours - hours_to_off) hours_left
            , IF(hours - hours_to_off >= 0, 1, 0) overlap
        FROM (
            SELECT source, correct, hours, off_long
                , (24 - off_long) on_long
                , HOUR(TIMEDIFF(DATE(source) + INTERVAL off_start HOUR, source)) hours_to_off
            FROM tt
          ) t
      ) t
  ) t
--------------

+---------------------+---------------------+--------------+---------------------+
| source              | correct             | hours_to_end | ending              |
+---------------------+---------------------+--------------+---------------------+
| 2010-11-11 12:00:00 | 2010-11-11 13:00:00 |       1.0000 | 2010-11-11 13:00:00 |
| 2010-11-11 19:00:00 | 2010-11-12 06:00:00 |      11.0000 | 2010-11-12 06:00:00 |
| 2010-11-11 19:00:00 | 2010-11-12 07:00:00 |      12.0000 | 2010-11-12 07:00:00 |
| 2010-11-11 19:00:00 | 2010-11-12 08:00:00 |      13.0000 | 2010-11-12 08:00:00 |
| 2010-11-11 19:00:00 | 2010-11-13 15:00:00 |      44.0000 | 2010-11-13 15:00:00 |
| 2010-11-11 19:00:00 | 2010-11-15 11:00:00 |      88.0000 | 2010-11-15 11:00:00 |
| 2010-11-11 19:00:00 | 2010-11-17 07:00:00 |     132.0000 | 2010-11-17 07:00:00 |
+---------------------+---------------------+--------------+---------------------+

Редактировать : вот более короткая версия:

SELECT source, correct
  , source
    + INTERVAL LEAST(hours, hours_to_off)
      + IF(hours-hours_to_off >= 0
        ,(hours-hours_to_off-MOD(hours-hours_to_off, on_long))/on_long*24
          + off_long + MOD(hours-hours_to_off, on_long)
        ,0) HOUR ending
FROM (
    SELECT source, correct, hours, off_long, (24-off_long) on_long
      , HOUR(TIMEDIFF(DATE(source)+INTERVAL off_start HOUR, source)) hours_to_off
    FROM tt
  ) t
;
1 голос
/ 18 ноября 2010

А это мое:

CREATE PROCEDURE do_update()
BEGIN

DECLARE @offhoursperday, @hours, @days, @remaininghours INT
DECLARE @offhoursstart, @offhoursend TIME

SET @offhoursstart = CAST('22:00' AS TIME)
SET @offhoursend = CAST('06:00' AS TIME)
SET @hours = 54
SET @days = @hours / (24 - @offhoursperday)
SET @remaininghours = @hours % (24 - @offhoursperday)

UPDATE table T 
   SET T.ending =  
   CASE 
       WHEN ((HOUR(TIMEDIFF(@offhoursstart, TIME(T.ending))) + 24) % 24) < @remaininghours
       THEN DATE_ADD(DATE_ADD(T.ending, INTERVAL @days DAY), INTERVAL @remaininghours HOUR)
       ELSE DATE_ADD(DATE_ADD(T.ending, INTERVAL @days DAY), INTERVAL (@remaininghours + @offhoursperday) HOUR)
   END

END
...