2011-04-24 37 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;