2012-03-19 61 views
2

這是我會像能夠做到:如何存儲MySQL間隔類型?

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中以任何方式得到支持,或者您是否有這種巧妙的破解?

謝謝;你搖滾。

回答

0

這裏的簡單的方法。它工作速度相當快。如果您覺得您會更頻繁地碰到其他人,您可以更改開關語句的順序以優化速度。我沒有對克里斯·哈欽森的解決方案做出反應。由於動態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 // 
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周)
+0

或者,您可以使用時間刻度間隔(如秒,分鐘或小時),然後執行所有日期/時間操作。 – 2012-03-20 00:00:15

+0

哇,怪物秀。有趣的解決方案。儘管如此,即使在服務器上執行,也可能是性能問題,因爲每個語句都需要在執行前先準備好。對於一兩個人來說不算什麼大事,但幾千人就會加起來。在這種情況下,將所有計算減少爲「秒」不起作用,因爲MySQL處理間隔的默認方式有點模糊。 2012年1月1日+ INTERVAL 1年將在2013年1月1日結束。如果減少到秒,由於days_per_month和閏年等原因,會產生一些怪異的結果。 – leiavoia 2012-03-20 00:52:25

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); 
+0

我認爲這個解決方案已被棄用,因爲DATETIME默認不再支持零值(sql_mode NO_ZERO_IN_DATE:http://dev.mysql。 com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_zero_in_date)。 – Tarsis 2016-06-08 13:32:17