mysql根據周查詢統計,比如week()或者DATE_FORMAT或者跨年要注意的幾點

目錄

 

前言:

周的劃分情況:

1.周的起始

2.周的跨年

3.一年有多少周?

Mysql的做法:

每週的第一天:

返回值區間:

如何得出返回值是1:

 總結:

其他:


前言:

周檢索和月檢索是不一樣的,月檢索是超級簡單。

但是周檢索稍不注意,就會入坑,而且是很久之後才發現的,比如元旦。

在詳細接觸周檢索之前,你需要了解一些關於周的知識。

周的劃分情況:

1.周的起始

每週的第一天是從周天算呢還是從週一算呢,這個比較坑的,各個國家有各個國家的國歌的。

2.周的跨年

如下圖,2020年元旦的這一週包含幾個周?

它會根據不同地區的習俗習慣包括且不侷限於下面的情況:

1.包含一個周:2019.last 2019年的最後周

2.包含一個周:2020.1 2020年的第一個周

3.包含一個周:不按年劃分,以週日爲起點。

4.包含二個周:不按年劃分,以週一爲起點

5.包含三個周:既按年又按週一爲第一天,分別是2019.last1     2019.last2     2020.1

6.包含三個周:   嚴格按照週一爲第一天,分別是2019.last1     2019.last2     2020.0(因爲2020年的第一個週一還沒有出現)

....

....

3.一年有多少周?

有人會說是52周,這是常識。

有人會說53周,因爲52*7=364,還不到365天,即使閏年366天,那麼依然應該是53周。

但這都是不對的.我做了個圖片。諸多情況,如下所示:

第一種情況:

如果2019.1.1是週一,那麼到2019.12.30正好是週日,2019.12.31是新的週一。

爲什麼?因爲365/7=52--1啊。它整好是周的倍數餘1天。

那麼藍色代表第1周,橙色是52周,綠色是53周。

一共是53周。

第二種情況:

我們往後推2天,如果2019.1.1是週三,那麼應該如圖所示。和第一種情況一樣。

綠色是53周,橙色是52周。

一共是53周。

第三種情況:

我們往前提一天。如果2019.1.1是周天。那麼它和第一種情況正好相反,也肯定是53周。

此時黃色是第一週,橙色是53周。

一共是53周

第四種情況:

和第三種情況差不多,但如果2019年是個閏年,我們就會發現,已經有54周了,比如1916年。

 

所以,正確答案,應該是絕大部分是53周,如果是閏年且其首日是其所在周的最後一天時將達到54周。

~~~看完科普這麼努力,也不給個贊嗎?

 

Mysql的做法:

由於周的劃分還是相當的複雜的,mysql這塊爲了解決這個問題也是耗費了不少策略。

那麼我們在mysql的解決上,最應該先關注的是WEEK()函數。

比如:week("2019-03-01") = 8 代表着第八週。

week表達式是這樣的:week(date,[mode]);其中,date參數是日期,比如:“2019-01-01”,mode參數代表着如何判斷周,分別是0~7mode參數可以省略。

mode代表的意思如下:

Mode 每週的第一天 返回值區間 如何得出返回值是1
0 Sunday 0-53 從第一個Sun算
1 Monday 0-53 第一個超過或等於四天的周
2 Sunday 1-53 從第一個Sun算
3 Monday 1-53 第一個超過或等於四天的周
4 Sunday 0-53 第一個超過或等於四天的周
5 Monday 0-53 從第一個MON算
6 Sunday 1-53 第一個超過或等於四天的周
7 Monday 1-53 從第一個MON算

每週的第一天:

這個很好理解。如果我們選擇mode的話,在中國,一般會選擇1357,而不是0246.

返回值區間:

我們上面已經說過了,對於計算機而言,每年的周有53周,偶爾會來個54周。返回值0~53是很正常的。

可爲什麼會有1~53呢?這不是少一個嗎?

那是因爲內部的算法,即使在閏年且首日是其所在周的最後一天時,也會將首日或最後一日算到鄰年裏面,保證其最大值就是53。

不過這樣的,就會產生不好的情況,和我們的需求可能不相符合,有時候我們怎能願意將元旦統計到去年的數據裏面呢?

所以這時我們可以過濾掉1~53的了。

那麼最終剩下的就是1和5

如何得出返回值是1:

要以此圖爲例

從第一個Sun算:

意思是從該年的第一個星期日開始才能算第一週。

那麼像上面這張圖,1號~5號算是第幾周呢?

這還要根據返回值區間來算,如果區間是0~53,那麼是第0周。如果是1~53,那麼是去年的52~53周。

從第一個MON算:

跟從第一個Sun差不多

意思是從該年的第一個星期一開始才能算第一週。

那麼像上面這張圖,1號~6號算是第幾周呢?

這還要根據返回值區間來算,如果區間是0~53,那麼是第0周。如果是1~53,那麼是去年的52~53周。

第一個超過或等於四天的周:

一個周有7天,不可能出現跨年時兩年擁有本週的天數一致的情況,總有一個多一個少。如果某年擁有的天數超過4或者等於4的話,那麼他所擁有的天數就多一些。

如果某年擁有跨年周天數多的話,則這是它的第一週。

如上圖,第一行則是第1周,那麼第一週的結束還要根據每週的第一天才能知道是截至到星期一還是星期天。

如果某年擁有的跨年周天數少呢?

那麼下一週纔是它的第一週,那麼當前跨年這塊是第幾周呢?

這依然還要根據返回值區間來算,如果區間是0~53,那麼是第0周。如果是1~53,那麼是去年的52~53周。

而且第一週的結束也要根據每週的第一天 計算

 總結:

我們可以做張表,來查看效果。下表是days表.有days和dis兩個字段.

其中2019年擁有跨年周的天數較多,我在描述裏寫了是大,另外2019-01-06是週日,2019-01-07是週一.

其中2021年擁有跨年周的天數較少,我在描述裏寫了是小,.......

執行sql語句,依次往裏面塞入mode分別爲0~7

SELECT 
days,dis,
WEEK(days,0) 0a,
WEEK(days,1) 1a,
WEEK(days,2) 2a,
WEEK(days,3) 3a,
WEEK(days,4) 4a,
WEEK(days,5) 5a,
WEEK(days,6) 6a,
WEEK(days,7) 7a 
FROM days ORDER BY days

結果如下:

大家要重點關注1和5

可以發現區別.

當mode=1且新年跨年周是大周的時候,是1

當mode=5且新年跨年周是大周的時候,是0

我們再翻查mode表格,確實如表格記載.

現在我們有1和5兩個選擇,那麼選擇哪個呢?

我傾向於選擇5,不必考慮大小周,就按週一來。當然有特殊需要的朋友可以選擇其他的。

 

其他:

1.week函數可以省略mode,mode的默認值來自於系統變量default_week_format而系統變量default_week_format默認是0.

也就是說,如果選擇其他的,要麼你更改系統變量,要麼就別省略mode.

這裏建議你永遠別省略mode.因爲你可能將來會換mysql,那時候忘了修改變量就坑了。

2.YEARWEEK(date,【mode】)這個和week()差不多,它返回的大概是201952這樣的。

但是它的mode省略的話,默認值是0,而不是default_week_format

3.DATE_FORMAT(date,format)函數關於周要注意的地方

它只有下面這些東西。其中%X是用來表示年的,和%V是一起使用的。

%U 00.. 53,週日是一週的第一天; WEEK()模式0
%u 00.. 53,週一是一週的第一天; WEEK()模式1
%V 01.. 53,週日是一週的第一天; WEEK()模式2; 用於 %X
%v 01.. 53,週一是一週的第一天; WEEK()模式3; 用於 %x
%X 星期日是第一天,用於%V
%x 星期一是第一天, 用於%v

因爲沒有mode=5,所以我是不樂意用的,有用的同學要注意了。 

呼呼呼呼~~寫完了。好累哦 

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