Mysql 中使用DATE_FORMAT函數按月、周統計數據

項目中的統計報表作的很多,需求中有按周、月統計數據的。查看了Mysql的API,發現Date_format是格式化日期的,看了Date_format()的具體說明後就用這個函數按周統計,sql大致如下:

select   DATE_FORMAT(check_date ,'%X-%V')  dates,avg(weight)/10000  weight from ho_body where user_id=295

 and  weight >0 and check_date  between '2009-02-24' and '2010-02-24' group by dates

------------------------------------------------------------------------------------------------------

查出的結果爲:

dates       weight

2009-30   80.9
2009-31   80.425
2009-32   80.76666667
2009-33   80.75384615
2009-34   80.8
2009-35   79.88
2009-36   80.06
2009-37   79.875
2009-38   79.075
2009-39   79.26666667
2009-40   79.16666667
2009-41   78.875
2009-42   78.33333333
2009-43   78.77272727
2009-44   77.625
2009-45   77.825
2009-46   77.575
2009-47   77.45
2009-48   81.25
2009-49   76.5
2009-50   77.83333333
2009-52   79.8
2010-02   79.2

 

 

%X

年,其中的星期日是周的第一天,4 位,與 %V 使用

%x

年,其中的星期一是周的第一天,4 位,與 %v 使用

%Y

年,4

%y

年,2 位

 

難道%X只能與%V一起用表示年-周,並且週日爲一週開始,

%x與%v一起用,表示年-周,週一爲一週開始?

再看到前面的

 

%V

(01-53) 星期日是一週的第一天,與 %X使用

%v

(01-53) 星期一是一週的第一天,與 %x使用

看來是這個意思了,我之前怎麼就沒有注意到這個特別之處呢?可能是當時作完以周統計,然後再寫月統計時,一看m表示月,數值,就直接把Date_format('%X-%V')改爲Date_format('%X-%m')了。再加上%Y年,4位,%m月,沒有具體說明,所以一直沒有發現,並且用%X-%m按月統計,測試了許多數據,發現年-月,數值全是正確的。結果在跨年的情況下有問題了。。。一般情況下我是會考慮跨年的情況的,比如在求一個日期屬於這一年的第幾周,在這個問題上,我測試2009-12-31,2010-01-01屬於哪一週,2010-01-03是哪一週,發現之前的方法有bug,後來作了修正才正確。而這是用mysql函數統計,測試一些數據沒問題就覺得ok了,根本沒有想到這樣寫在跨年時有問題了。。。。

 

爲了將這個問題徹底整理清楚,下面是我找到的詳細解讀:

Date_format可以使用的格式有:

 

格式

描述

%a

縮寫星期名

%b

縮寫月名

%c

月,數值

%D

帶有英文前綴的月中的天

%d

月的天,數值(00-31)

%e

月的天,數值(0-31)

%f

微妙

%H

小時 (00-23)

%h

小時 (01-12)

%I

小時 (01-12)

%i

分鐘,數值(00-59)

%j

年的天 (001-366)

%k

小時 (0-23)

%l

小時 (1-12)

%M

月名

%m

月,數值(00-12)

%p

AM 或 PM

%r

時間,12-小時(hh:mm:ss AM 或 PM)

%S

秒(00-59)

%s

秒(00-59)

%T

時間, 24-小時 (hh:mm:ss)

%U

周 (00-53) 星期日是一週的第一天

%u

周 (00-53) 星期一是一週的第一天

%V

(01-53) 星期日是一週的第一天,與 %X使用

%v

(01-53) 星期一是一週的第一天,與 %x使用

%W

星期名

%w

周的天 (0=星期日, 6=星期六)

%X

年,其中的星期日是周的第一天,4 位,與 %V使用

%x

年,其中的星期一是周的第一天,4 位,與 %v使用

%Y

年,4

%y

年,2 位

 

Mysql中還有另外幾種返回日期的函數,如:

SELECT  EXTRACT(YEAR_MONTH  FROM  datecolum ) 返回格式如200902

EXTRACT() 函數用於返回日期/時間的單獨部分,比如年、月、日、小時、分鐘等等。

語法

EXTRACT(unit FROM date)

date 參數是合法的日期表達式。unit 參數可以是下列的值:

 

Unit 值

MICROSECOND

SECOND

MINUTE

HOUR

DAY

WEEK

MONTH

QUARTER

YEAR

SECOND_MICROSECOND

MINUTE_MICROSECOND

MINUTE_SECOND

HOUR_MICROSECOND

HOUR_SECOND

HOUR_MINUTE

DAY_MICROSECOND

DAY_SECOND

DAY_MINUTE

DAY_HOUR

YEAR_MONTH

 

Unit 值

MICROSECOND

SECOND

MINUTE

HOUR

DAY

WEEK

MONTH

QUARTER

YEAR

SECOND_MICROSECOND

MINUTE_MICROSECOND

MINUTE_SECOND

HOUR_MICROSECOND

HOUR_SECOND

HOUR_MINUTE

DAY_MICROSECOND

DAY_SECOND

DAY_MINUTE

DAY_HOUR

YEAR_MONTH

 

檢查了一下,大致沒有問題,然後又開始尋找如何按月統計,然後就看Date_format的語法,

%m表示數值,%M表示名稱,看後很興奮的試一下:

select   distinct  DATE_FORMAT(check_date ,'%X-%m')  c1,avg(weight)/10000  wei from ho_body where user_id=295
 and  weight >0 and check_date  between '2009-02-24' and '2009-10-31' group by c1

——————————————————————————————————————

c1               wei

2009-08    80.66388889
2009-09    79.70555556
2009-10    78.83714286

 

然後測試這樣計算的結果是否正確,經過測試,果然是沒問題的,很有成就感。然後就用這個方法統計,拿取數據,然後將這些統計的結果作爲數據集,用JfreeChart畫圖。後期測試時,發現畫的統計圖橫軸日期有問題,時間範圍爲2009-02-24~2010-02-24時,圖片中竟然多出一個2009年1月,並且在最右側。我確信我是經過排序的,不可能2009年1月會在最右側,之後再調試,竟然發現數據庫中根本就沒有09年1月的數據,更直觀的錯誤是,以between '2009-02-24' and '2009-10-31' 條件,根本不可能出現2009-01。

 

然後將錯誤原因定位在sql語句上,執行這個語句,果然,原因就在這裏:

select   distinct  DATE_FORMAT(check_date ,'%X-%m')  c1,avg(weight)/10000  wei from ho_body where user_id=295
 and  weight >0 and check_date  between '2009-02-24' and '2010-02-24' group by c1

————————————————————————————————————————

c1              wei

2009-01    79.8
2009-08    80.66388889
2009-09    79.70555556
2009-10    78.83714286
2009-11    77.64285714
2009-12    78.75
2010-01    79.2

這個09年1月到底是哪裏出來的,我先確定2009年1月是否有數據,結果測試最早的數據爲2009-08-01,並沒有1月的任何數據。既然最早的數據是8月,那麼就測試這個多出來的2009-01是從哪裏冒出來的。

我就用最笨的方法測試:
select  distinct DATE_FORMAT(check_date ,'%X-%m')c1   from ho_body where user_id=295 and check_date  between '2009-08-01' and '2009-08-31' order by c1

————————————————————————————————————————

c1

2009-08

問題不在8月。繼續測試:

select  distinct DATE_FORMAT(check_date ,'%X-%m')c1   from ho_body where user_id=295 and check_date  between '2009-9-01' and '2009-09-30' order by c1

——————————————————————————————————————

 

c1

2009-09

 

……

……

直到2010年時,


select  distinct DATE_FORMAT(check_date ,'%X-%m')c1   from ho_body where user_id=295 and check_date  between '2010-01-01' and '2010-01-31' order by c1

————————————————————————————————————————

c1

2009-01
2010-01

問題就是2010年1月,並且,如果將條件改爲between '2010-01-02' and '2010-01-31' 則不會多出2009-01。難道是Date_format函數有bug,在跨年時沒有考慮正確,將2010年1月1日歸爲2009年的1月中?當然我也有懷疑過是我的sql語句有問題,仔細再看了看Date_format()的語法,

%X表示年,週日爲一週第一天

%x表示年,週一爲一週第一天

%M表示月,名稱

%m表示月,數值,01形式

%V表示周,週日爲第一天

%v表示周,週一爲第一天

...........

 

看來看去,感覺沒什麼錯誤呀,感覺自己對這個研究的夠清楚明白了,一定沒有問題的。

mysql有bug的想法我堅持了一下午,在我和一個同事說這個bug的時候,老大聽到了,問我具體怎麼回事,我就給她講解,特別奇怪的地方在於數據庫根本沒有09年1月的數據,用mysql中的Date_format的按月統計函數時,在跨年時有問題。老大也覺得這個問題不可思議,這時那個同事說,你怎麼用X表示年呀,一般不都是有Y表示年嗎?我還反駁說,這個沒區別的呀,都是一樣的,表示年嘛,4位的。。。。

後來和他爭論之中,爲了表明修改這個X,Y什麼的沒效果,我就改成了%Y-%m,結果卻是2009-01沒有了!!!!

怎麼會這樣????也太低級了吧,之前一直懷疑mysql的bug,竟然是這個原因?然後再仔細看Date_format()的語法,看後快暈過去了,這麼低級的錯誤我怎麼之前一直沒有發現呢?

 

%M

月名

%m

月,數值(00-1


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章