2011-11-20 58 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