2011-11-20 61 views
1

我的表中有一列叫做expiry_date。我使用下面的查詢返回此日期,加上6個月:我該如何做這個日期計算?

SELECT DATE_ADD(expiry_date, INTERVAL 6 MONTH) AS expiry_date; 

我想修改上面的,這樣如果expiry_date加6個月過去(CURRENT_DATE之前),另外6個月根據需要添加多次,直到日期爲止。

我該如何使用MySQL來做到這一點?

+0

'expiry_date'是什麼格式? – MyStream

+1

@MyStream:這是'DATE'字段 – gjb

+1

請不要標記您的標題。 –

回答

2

第一種方法:

SELECT 
    case when expiry_date > SYSDATE() then 
     DATE_ADD( expiry_date , INTERVAL 6 MONTH) 
    else 
     DATE_ADD(
      DATE_SUB( 
      SYSDATE(), 
      INTERVAL 
      (DATEDIFF(SYSDATE(), expiry_date) % (6 * 30)) 
      MONTH 
     ) 
      , 
      INTERVAL 6 MONTH) 
    end 
    AS expiry_date 
FROM ... 

未經測試。

+0

這裏的30天值是否與計算的INTERVAL值一樣準確? (我不知道差別 - 要求清楚。) – MyStream

+0

不,這個答案其實是錯誤的。根據日期的不同,增加5,6或7個月。 –

1

我用下面的數據來測試這一點:

Table: `test` 
uid  expiry_date 
1  2011-11-03 
2  2011-01-20 

代碼:

SELECT 
    `uid`, 
    `expiry_date`, 
    PERIOD_DIFF(
     date_format(DATE_ADD(CURDATE(),INTERVAL 1 DAY),'%Y%m'), 
     date_format(`expiry_date`,'%Y%m') 
    ) as `dif`, /* Straight Month Difference */ 
    CEIL(PERIOD_DIFF(
     date_format(DATE_ADD(CURDATE(),INTERVAL 1 DAY),'%Y%m'), 
     date_format(`expiry_date`,'%Y%m') 
    )/6) AS `dif2`, /* How many blocks of 6 months, rounded up */ 
    (
     IF(
      (/* If 1 block is > today, add the 6 months and finish */ 
      DATE_ADD(
       CURDATE(), 
       INTERVAL 1 DAY 
      ) < DATE_ADD(
       `tOuter`.`expiry_date`, 
       INTERVAL 6 MONTH 
      ) 
     ), /* this is with just 6 months added */ 
     DATE_ADD(
      `tOuter`.`expiry_date`, 
       INTERVAL 6 MONTH 
      ), /* this works out how many blocks of 6 months to add */ 
      DATE_ADD(
       `tOuter`.`expiry_date`, 
      INTERVAL (
       6 * CEIL(/* round up number of months */ 
        PERIOD_DIFF(/* get number of months */ 
         date_format(
          DATE_ADD(
           CURDATE(), 
           INTERVAL 1 DAY 
          ), 
          '%Y%m' 
         ), 
         date_format(
          `expiry_date`, 
          '%Y%m' 
         ) 
        )/6 /* divide months by 6 to match question */ 
       ) 
      ) MONTH /* add the dynamically calculated interval */ 
     ) 
    ) 
) AS `expiry_date_calculated` FROM `test` AS `tOuter` 

它導致:

uid  expiry_date  dif   dif2  expired_date_calculated 
1  2011-11-03  0   0   2012-05-03 
2  3011-01-20  10   2   2012-01-20 

這是此輸入所需的輸出?

性能備註:這在性能上很糟糕,我邀請其他人建議更高效的例程。這可能會更好地寫成一個存儲過程,並且如果您將CURDATE()的日期作爲字符串傳遞,那麼它肯定會更好。

示例:使用2個字段,需要0.04秒來產生上述所需的結果。

編輯:較小的版本:

SELECT 
`id`, `expiry_date`, 
(IF((DATE_ADD(CURDATE(),INTERVAL 1 DAY) < DATE_ADD(`expiry_date`,INTERVAL 6 MONTH)), 
    DATE_ADD(`expiry_date`,INTERVAL 6 MONTH), 
    DATE_ADD(`expiry_date`, 
    INTERVAL (6 * CEIL(PERIOD_DIFF(
     date_format(DATE_ADD(CURDATE(),INTERVAL 1 DAY),'%Y%m'), 
     date_format(`expiry_date`,'%Y%m') 
    )/6)) MONTH 
    ) 
) 
) AS `expiry_date_calculated` 
0

您應該添加任何X年6個月X年和12個月你EXPIRY_DATE。 X是他們今年的部分現在()和expiry_date之間的差異。

select if(dayofyear(expiry_date)>=dayofyear(now()), 
date_add(test, interval concat(year(now())-year(expiry_date), '-6') year_month), 
date_add(test, interval concat(year(now())-year(expiry_date), '-12') year_month)) 
as expiry_date from <table>; 

一個例子。 EXPIRY_DATE是2009-10-01

DAYOFYEAR(EXPIRY_DATE)是274

DAYOFYEAR(現在的())是325

所以第一個條件是假的。 concat(year(now())-year(expiry_date), '-12'給出2011-2009 = 2年和12個月(字符串是'2-12'),並且用於date_add('2009-10-01', interval '2-12' year_month即2011-10-01 + 6個月= 2012-05-01。

+0

這隻適用於6個月的2個時間間隔,我認爲海報正在尋找可能數量可變的時間間隔。 – MyStream

+0

我的查詢將始終返回一個未來的值,並且始終是初始值的6個月的倍數。我認爲這是海報想要的:)注意「X年」部分。 –

+0

啊 - 非常好:)只需重新閱讀它 - 簡潔。如果我的答案是upvoted,請upvote這個答案,因爲它更簡潔,可能更有效。 – MyStream