Как я могу сохранить тип интервала MySQL? - PullRequest
2 голосов
/ 20 марта 2012

Это то, что я хотел бы , чтобы иметь возможность:

SET @interval_type := MONTH;
SELECT '2012-01-01' + INTERVAL 6 @interval_type;
+------------+
|'2012-06-01'|
+------------+

И, конечно, это не работает, и в MySQL отсутствует тип данных "интервал".

Я хочу иметь возможность хранить значение интервала и тип интервала в таблице, чтобы база данных могла быстро выполнять математику естественным образом, без необходимости писать большой оператор switch, ala

... ELSE IF (type = 'MONTH') { SELECT @date + INTERVAL @value MONTH; } ... 

Поддерживается ли это каким-либо образом в MySQL или у вас есть умный взлом для этого?

Спасибо;Вы качаетесь.

Ответы [ 3 ]

4 голосов
/ 24 июля 2014

Это решение может пригодиться кому-то, кто реализует очередь заданий для cron или чего-то подобного.

Предположим, у нас есть справочная дата (DATETIME) и интервал повторения.Мы хотели бы сохранить оба значения в базе данных и получить быстрое сравнение, если уже пора выполнять и включить задание в очередь выполнения или нет.Интервал может быть нетривиальным, например (1 ГОД 12 ДНЕЙ 12 ЧАСОВ), и управляется мудрым пользователем (администратором), так что пользователь не собирается использовать значения, превышающие диапазон обычного типа данных DATETIME, иначе преобразование должно быть выполнено первым.(18 МЕСЯЦЕВ -> 1 ГОД 6 МЕСЯЦЕВ).

Затем мы можем использовать тип данных DATETIME для хранения как значений, так и контрольной даты и интервала.Мы можем определить сохраненную функцию, используя:

DELIMITER $$

CREATE DEFINER=`my_db`@`%` FUNCTION `add_interval`(`source` DATETIME, `interval` DATETIME) RETURNS datetime
BEGIN
  DECLARE result DATETIME;

  SET result = `source`;
  SET result=DATE_ADD(result, INTERVAL EXTRACT(YEAR FROM `interval`) YEAR);
  SET result=DATE_ADD(result, INTERVAL EXTRACT(MONTH FROM `interval`) MONTH);
  SET result=DATE_ADD(result, INTERVAL EXTRACT(DAY FROM `interval`) DAY);
  SET result=DATE_ADD(result, INTERVAL EXTRACT(HOUR FROM `interval`) HOUR);
  SET result=DATE_ADD(result, INTERVAL EXTRACT(MINUTE FROM `interval`) MINUTE);
  SET result=DATE_ADD(result, INTERVAL EXTRACT(SECOND FROM `interval`) SECOND);

RETURN result;
END

Затем мы можем сделать арифметику DATETIME, используя эту функцию, например,

// test solution
SELECT add_interval('2014-07-24 15:58:00','0001-06-00 00:00:00');

// get job from schedule table
SELECT job FROM schedule WHERE add_interval(last_execution,repetition)<NOW();

// update date of executed job
UPDATE schedule SET last_execution=add_interval(last_execution,repetition);
1 голос
/ 20 марта 2012

Вы можете решить эту проблему, используя подготовленные операторы, учитывая, что языковая конструкция недоступна для использования. Преимущество в том, что вы получаете производительность и гибкость, которые вам нужны; это может быть легко помещено в хранимую процедуру или функцию для добавленной стоимости:

SET @date = '2012-01-01';
SET @value = 6;
SET @type = 'MONTH';

SET @q = 'SELECT ? + INTERVAL ? ';
SET @q = CONCAT(@s, @type);

PREPARE st FROM @q;
EXECUTE st USING @date, @value;

В качестве альтернативы, в зависимости от вашей архитектуры базы данных / программного обеспечения и типа предполагаемых интервалов даты / времени, вы можете просто решить эту проблему, используя интервал шкалы времени:

SELECT @date + INTERVAL @value SECOND
  • 1 секунда - 1
  • 1 минута - 60
  • 1 час - 3600
  • 1 день - 86400 (24 часа)
  • 1 неделя - 604800 (7 дней)
  • 1 месяц - 2419200 (4 недели)
0 голосов
/ 23 марта 2012

Вот упрощенный подход.Работает достаточно быстро.Вы можете изменить порядок операторов switch, чтобы оптимизировать скорость, если вы чувствуете, что будете бить некоторых чаще, чем других.Я не сравнивал это с решением Криса Хатчинсона.Я столкнулся с проблемами, пытаясь обернуть это в хорошую функцию из-за динамического SQL.В любом случае, для потомков это гарантированно сработает:

CREATE FUNCTION AddInterval( date DATETIME, interval_value INT, interval_type TEXT  ) 
RETURNS DATETIME
DETERMINISTIC
BEGIN
    DECLARE newdate DATETIME;
    SET newdate = date;

    IF interval_type = 'YEAR' THEN
        SET newdate = date + INTERVAL interval_value YEAR;
    ELSEIF interval_type = 'QUARTER' THEN
        SET newdate = date + INTERVAL interval_value QUARTER;
    ELSEIF interval_type = 'MONTH' THEN
        SET newdate = date + INTERVAL interval_value MONTH;
    ELSEIF interval_type = 'WEEK' THEN
        SET newdate = date + INTERVAL interval_value WEEK;
    ELSEIF interval_type = 'DAY' THEN
        SET newdate = date + INTERVAL interval_value DAY;
    ELSEIF interval_type = 'MINUTE' THEN
        SET newdate = date + INTERVAL interval_value MINUTE;
    ELSEIF interval_type = 'SECOND' THEN
        SET newdate = date + INTERVAL interval_value SECOND;
    END IF;

    RETURN newdate;
END //

Это идет с таким же упрощенным тестом:

CREATE FUNCTION `TestInterval`( numloops INT ) 
RETURNS INT
DETERMINISTIC
BEGIN
    DECLARE date DATETIME;
    DECLARE newdate DATETIME;
    DECLARE i INT; 
    SET i = 0;

    label1: LOOP
        SET date = FROM_UNIXTIME(RAND() * 2147483647);
        SET newdate = AddInterval(date,1,'YEAR');
        SET i = i+1;
        IF i < numloops THEN
            ITERATE label1;
        ELSE
            LEAVE label1;
        END IF;
    END LOOP label1;
    return i;
END //
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...