如何存储MySQL间隔类型?

时间:2012-03-19 23:39:15

标签: mysql date time intervals

这就是我喜欢能够做到的事情:

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 个答案:

答案 0 :(得分:4)

对于为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 :(得分:1)

考虑到没有可用的语言结构,您可以使用预准备语句解决此问题。这样做的好处是可以获得所需的性能和灵活性;这可以很容易地放在存储过程或函数中以增加价值:

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周)

答案 2 :(得分:0)

这是简单的方法。它工作得相当快。您可以更改switch语句的顺序以优化速度,如果您觉得您将比其他人更频繁地击中它们。我没有反对Chris Hutchinson的解决方案。由于动态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 //