【问题标题】:How can I store a MySQL interval type?如何存储 MySQL 间隔类型?
【发布时间】:2012-04-04 11:47:16
【问题描述】:

这是我希望能够做到的:

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 是否以任何方式支持此功能,或者您对此有什么巧妙的破解方法?

谢谢;你摇滚。

【问题讨论】:

    标签: mysql date time intervals


    【解决方案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 周)

    【讨论】:

    • 另外,您可以使用时间刻度间隔,例如秒、分钟或小时,并以这种方式执行所有日期/时间操作。
    • 哇,畸形秀。有趣的解决方案。即使在服务器上执行,这也可能是性能问题,因为每个语句都需要在执行之前先准备好。一两个人没什么大不了的,但加起来几千。在这种情况下,将所有计算减少到“秒”不起作用,因为 MySQL 处理间隔的默认方式有点模糊。 2012-01-01 + INTERVAL 1 YEAR 将导致 2013-01-01。如果减少到秒,由于 days_per_month 和闰年等原因,它会产生一些奇怪的东西。
    【解决方案2】:

    这是简单的方法。它的工作速度相当快。如果您觉得您会比其他人更频繁地点击,您可以更改 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 //
    

    【讨论】:

      【解决方案3】:

      对于为 cron 或类似任务实现作业队列的人来说,此解决方案可能会派上用场。

      假设我们有一个参考日期 (DATETIME) 和重复间隔。我们希望将这两个值存储在数据库中,并快速比较是否已经到了执行时间并将作业包含到执行队列中。 间隔可能很重要,例如(1 YEAR 12 DAYS 12 HOUR) 并由明智的用户 (admin) 控制,因此用户不会使用超出常规 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);
      

      【讨论】:

      猜你喜欢
      • 2011-05-28
      • 2016-04-11
      • 1970-01-01
      • 2010-12-19
      • 2015-08-25
      • 1970-01-01
      • 2012-04-21
      • 2017-08-20
      • 2011-06-27
      相关资源
      最近更新 更多