2011-04-24 76 views
2

我有2天check_in(25/04/2011)和check_out(04/06/2011)。现在我需要计算月份之间日期之间的日期。用于计算2dates组之间的天数的MySQL查询

即。月 - 天,

April - 5, 
May - 31, 
June - 4, 

请帮我建立mysql查询以获得上述结果。 在此先感谢。

+3

你会更好的计算这个客户端。 MySQL有很棒的日期函数,但是你会使查询不必要地复杂 – 2011-04-24 19:04:12

+0

问题是我需要查询来生成报告。否则,我可能不得不编写程序逻辑。 – Surya 2011-04-24 20:15:02

+0

你会如何使用输出?这些行是新的选择,还是应该放在1列中? – Pentium10 2011-04-24 20:20:03

回答

0

使用TO_DAYS(日期)函数。

+0

事情是我需要计算check_in(25/04/2011)和check_out(04/06/2011)之间的差异。使用datediff()我得到的答案为40天。但我希望具体如上所述。即4月5日, 5月31日, 6月4日, – Surya 2011-04-24 18:51:42

3

如果你想严格在MySQL中完成,你需要创建一个存储过程来做到这一点。

类似于存储过程(这个范围不超过一年)这样的东西。

DROP PROCEDURE IF EXISTS `getDateDiffBreakdown`; 
CREATE PROCEDURE `getDateDiffBreakdown`(_DATE1 DATE,_DATE2 DATE) 
BEGIN 

IF (MONTH(_DATE1)<>MONTH(_DATE2)) THEN 
-- we detected a month change 
-- compute the selection based on current date and last day of month 
SELECT CONCAT(DATE_FORMAT(_DATE1,'%M'),' - ',TO_DAYS(LAST_DAY(_DATE1))-TO_DAYS(_DATE1)+1); 
-- step into next month and re-run the calc 
call getDateDiffBreakdown(DATE_ADD(LAST_DAY(_DATE1),INTERVAL 1 DAY),_DATE2); 

ELSE 
-- same month, do the calculation 
SELECT CONCAT(DATE_FORMAT(_DATE1,'%M'),' - ',TO_DAYS(_DATE2)-TO_DAYS(_DATE1)+1); 
END IF; 

END; 

调用是这样的:

set max_sp_recursion_depth = 11; 
call getDateDiffBreakdown('2011-12-11','2012-06-03'); 

UPDATE

在另一种方法在1号线搞定,那就是:

​​

调用是这样的:

set max_sp_recursion_depth = 255; 
set @TEMP = ''; 
call getDateDiffBreakdown2('2011-12-11','2012-06-03',@TEMP); 
SELECT @TEMP; 
+0

+1现在就测试您的解决方案。你总是很酷。 :) – 2011-04-24 21:42:52

+0

谢谢,我会让OP或其他人调整代码以适应从不同年份的多个月的范围工作。 – Pentium10 2011-04-24 21:44:36

1

我也试图解决这个问题。 Pentium10太强大了,现在我会尝试他的解决方案。 :) 顺便说一下,这是我的。

delimiter // 
drop procedure if exists groupDaysByMonth// 
create procedure groupDaysByMonth(in dStart date,in dEnd date) 
begin 
declare i int default 0; 
declare months,days int; 
drop table if exists t; 
create temporary table t (
month_year varchar(50), 
daysNum int 
); 
set months = (select period_diff(date_format(dEnd,'%Y%m'),date_format(dStart,'%Y%m'))); 
while i<=months do 
if months = 0 then 
set days = (select datediff(dEnd,dStart)); 
elseif i = 0 then 
set days = (select datediff(concat(date_format(dStart,'%Y-%m-'),day(last_day(dStart))),dStart)); 
elseif months = i then 
set days = (select datediff(dEnd,date_format(dEnd,'%Y-%m-01'))+1); 
else 
set days = (select day(last_day(dStart + interval i month))); 
end if; 
insert into t (month_year,daysNum) values(date_format(dStart + interval i month,'%M %Y'),days); 
set i = i + 1; 
end while; 
select * from t; 
end // 
delimiter ; 


mysql> call groupDaysByMonth('2011-04-25','2011-04-30'); 
+------------+---------+ 
| month_year | daysNum | 
+------------+---------+ 
| April 2011 |  5 | 
+------------+---------+ 
1 row in set (0.01 sec) 

mysql> call groupDaysByMonth('2011-04-25','2011-06-04'); 
+------------+---------+ 
| month_year | daysNum | 
+------------+---------+ 
| April 2011 |  5 | 
| May 2011 |  31 | 
| June 2011 |  4 | 
+------------+---------+ 
3 rows in set (0.01 sec) 

Query OK, 0 rows affected (0.01 sec) 


mysql> call groupDaysByMonth('2011-09-25','2012-05-02'); 
+----------------+---------+ 
| month_year  | daysNum | 
+----------------+---------+ 
| September 2011 |  5 | 
| October 2011 |  31 | 
| November 2011 |  30 | 
| December 2011 |  31 | 
| January 2012 |  31 | 
| February 2012 |  29 | 
| March 2012  |  31 | 
| April 2012  |  30 | 
| May 2012  |  2 | 
+----------------+---------+ 
9 rows in set (0.01 sec) 

Query OK, 0 rows affected (0.03 sec) 

希望它有帮助。

+0

谢谢,这是我想要的。让我试试这个。 – Surya 2011-04-25 06:03:48

1
Follow Answer 1 -- i am using it for multi year n the result set is month number with year and then the days of month format is "month number - last two digit of year - total days in month." 

you can change the format of display according your need 


**UPDATE** 

In another approach to get in 1 line, it would be: 

    DROP PROCEDURE IF EXISTS `getDateDiffBreakdown2`; 
    CREATE PROCEDURE `getDateDiffBreakdown2`(IN _DATE1 DATE,IN _DATE2 DATE, INOUT _RETURN VARCHAR(1000)) 
    BEGIN 

    IF (MONTH(_DATE1)<>MONTH(_DATE2)) THEN 
    -- we detected a month change 
    -- compute the selection based on current date and last day of month 
    SET _RETURN=CONCAT(_RETURN,DATE_FORMAT(_DATE1,'%M'),' - ',TO_DAYS(LAST_DAY(_DATE1))-TO_DAYS(_DATE1)+1); 
    SET _RETURN = CONCAT(_RETURN,","); 
    -- step into next month and re-run the calc 
    call getDateDiffBreakdown2(DATE_ADD(LAST_DAY(_DATE1),INTERVAL 1 DAY),_DATE2,_RETURN); 

    ELSE 
    -- same month, do the calculation 
    SET _RETURN=CONCAT(_RETURN,DATE_FORMAT(_DATE1,'%M'),' - ',TO_DAYS(_DATE2)-TO_DAYS(_DATE1)+1); 
    END IF; 

    END; 

call like this: 

    set max_sp_recursion_depth = 255; 
    set @TEMP = ''; 
    call getDateDiffBreakdown2('2011-12-11','2012-06-03',@TEMP); 
    SELECT @TEMP; 









I have applied this post in one of my requirement but i found it buggy. i can be wrong if any one prove it and provide a better solution. 

look how i am calling it and what i am getting : 

    set max_sp_recursion_depth = 255; 
    set @TEMP = ''; 
    call getDateDiffBreakdown2('2010-12-10' , '2011-12-10',@TEMP); 
    SELECT @TEMP; 


in result i get : '12 - 10 - 366' 

year is changed but month is same. 

i have tweaked the function as following: kindly let me know if some thing is strange. thanks 




DROP PROCEDURE IF EXISTS `getDateDiffBreakdown2`; 
    CREATE PROCEDURE `getDateDiffBreakdown2`(IN _DATE1 DATE,IN _DATE2 DATE, INOUT _RETURN VARCHAR(1000)) 
    BEGIN 

    IF(YEAR(_DATE1)<>YEAR(_DATE2)) THEN 

SET _RETURN=CONCAT(_RETURN,DATE_FORMAT(_DATE1,'%b - %y'),' - ',TO_DAYS(LAST_DAY(_DATE1))-TO_DAYS(_DATE1)+1); 
SET _RETURN = CONCAT(_RETURN,","); 
-- step into next month and re-run the calc 
call getDateDiffBreakdown2(DATE_ADD(LAST_DAY(_DATE1),INTERVAL 1 DAY),_DATE2,_RETURN); 

ELSEIF (MONTH(_DATE1)<>MONTH(_DATE2)) THEN 
    -- we detected a month change 
    -- compute the selection based on current date and last day of month 
    SET _RETURN=CONCAT(_RETURN,DATE_FORMAT(_DATE1,'%M'),' - ',TO_DAYS(LAST_DAY(_DATE1))-TO_DAYS(_DATE1)+1); 
    SET _RETURN = CONCAT(_RETURN,","); 
    -- step into next month and re-run the calc 
    call getDateDiffBreakdown2(DATE_ADD(LAST_DAY(_DATE1),INTERVAL 1 DAY),_DATE2,_RETURN); 

    ELSE 
    -- same month, do the calculation 
    SET _RETURN=CONCAT(_RETURN,DATE_FORMAT(_DATE1,'%M'),' - ',TO_DAYS(_DATE2)-TO_DAYS(_DATE1)+1); 
    END IF; 

    END;