Bagaimana cara mengelompokkan berdasarkan minggu di MySQL?

92

Server tabel Oracle menawarkan fungsi built-in TRUNC(timestamp,'DY'),. Fungsi ini mengonversi stempel waktu menjadi tengah malam pada hari Minggu sebelumnya. Apa cara terbaik untuk melakukannya di MySQL?

Oracle juga menawarkan TRUNC(timestamp,'MM')untuk mengubah stempel waktu menjadi tengah malam pada hari pertama bulan saat itu terjadi. Di MySQL, yang ini sangat mudah:

TIMESTAMP(DATE_FORMAT(timestamp, '%Y-%m-01'))

Tetapi DATE_FORMATtrik ini tidak akan berhasil selama berminggu-minggu. Saya mengetahui WEEK(timestamp)fungsinya, tetapi saya benar-benar tidak ingin nomor minggu dalam tahun ini; barang ini untuk pekerjaan bertahun-tahun.

O. Jones
sumber
maksud Anda trunc (sysdate, 'W'), bukan trunc (sysdate, 'DY')
David Aldridge
TRUNC(date, 'DY' )mendapat berminggu-minggu dengan hari Minggu mulai. 'W'mendapat awal hari Senin, setidaknya di sistem saya.
O. Jones

Jawaban:

123

Anda dapat menggunakan YEAR(timestamp)dan WEEK(timestamp), dan menggunakan kedua ekspresi ini di dalam SELECTdan GROUP BYklausa.

Tidak terlalu elegan, tapi fungsional ...

Dan tentu saja Anda juga dapat menggabungkan dua bagian tanggal ini dalam satu ekspresi, yaitu seperti

SELECT CONCAT(YEAR(timestamp), '/', WEEK(timestamp)), etc...
FROM ...
WHERE ..
GROUP BY CONCAT(YEAR(timestamp), '/', WEEK(timestamp))

Sunting : Seperti yang ditunjukkan Martin, Anda juga dapat menggunakan YEARWEEK(mysqldatefield)fungsi tersebut, meskipun hasilnya tidak ramah mata seperti rumus yang lebih panjang di atas.


Sunting 2 [3 1/2 tahun kemudian!]:
YEARWEEK(mysqldatefield)Dengan opsional argumen kedua ( mode) diatur ke 0 atau 2 mungkin adalah cara terbaik untuk menggabungkan dengan minggu lengkap (yaitu termasuk untuk minggu yang mengangkang selama 1 Januari), jika itu adalah apa yang diinginkan. The YEAR() / WEEK()Pendekatan awalnya diusulkan dalam jawaban ini memiliki efek membelah data dikumpulkan untuk seperti "mengangkangi" minggu di dua: satu dengan mantan tahun, satu dengan tahun baru.
Potongan bersih setiap tahun, dengan biaya memiliki hingga dua minggu parsial, satu di kedua ujung, sering diinginkan dalam akuntansi, dll. Dan untuk itu YEAR() / WEEK()pendekatannya lebih baik.

mjv
sumber
12
YEARWEEK()hasil INT(6)yang saya percaya akan lebih cepat untuk mengurutkan / bergabung / mengelompokkan dengan
KCD
@mjv: apa yang terjadi jika dua tahun berbagi minggu yang sama? seperti untuk ini 31-12-2012 Hingga 6-1-2013 (Senin hingga Minggu). apakah ada solusi untuk ini?
hardik
@hardik: lihat Sunting 2. Bergantung pada kebutuhan seseorang MINGGU TAHUN () mungkin merupakan kunci yang lebih baik untuk digabungkan, jika seseorang lebih suka bekerja dengan minggu-minggu lengkap daripada memisahkan minggu parsial terakhir / pertama dalam tahun ini.
mjv
@mjv inilah solusi lain untuk tautan itu
hardik
pastikan "cap waktu" bukan bilangan bulat, seperti yang saya miliki di tabel saya. WEEK (timestamp) menggunakan jenis kolom tanggal / timestamp sebagai argumen yang valid
Usman Shaukat
37

Jawaban yang diterima di atas tidak berhasil untuk saya, karena ini mengurutkan minggu berdasarkan urutan abjad, bukan urutan kronologis:

2012/1
2012/10
2012/11
...
2012/19
2012/2

Inilah solusi saya untuk menghitung dan mengelompokkan berdasarkan minggu:

SELECT CONCAT(YEAR(date), '/', WEEK(date)) AS week_name, 
       YEAR(date), WEEK(date), COUNT(*)
FROM column_name
GROUP BY week_name
ORDER BY YEAR(DATE) ASC, WEEK(date) ASC

Menghasilkan:

YEAR/WEEK   YEAR   WEEK   COUNT
2011/51     2011    51      15
2011/52     2011    52      14
2012/1      2012    1       20
2012/2      2012    2       14
2012/3      2012    3       19
2012/4      2012    4       19
B Tujuh
sumber
5
memesan berdasarkan tanggal ( ORDER BY date ASC) harus melakukan trik juga
Fender
36

Mengetahui itu ... itu sedikit rumit, tapi ini dia.

FROM_DAYS(TO_DAYS(TIMESTAMP) -MOD(TO_DAYS(TIMESTAMP) -1, 7))

Dan, jika aturan bisnis Anda menyatakan minggu Anda dimulai pada hari Senin, ubah -1menjadi -2.


Edit

Bertahun-tahun telah berlalu dan saya akhirnya sempat menulis ini. http://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/

O. Jones
sumber
@Ollie - Saya akan mempertimbangkan untuk menggunakan DAYOFWEEK () atau WEEKDAY () untuk membantu keterbacaan.
martin clayton
1
Martin, saya mempertimbangkannya dan menemukan bahwa fungsi-fungsi itu berjalan 0-6 untuk Senin-Minggu. Aturan bisnis saya mengatakan bahwa minggu dimulai pada hari Minggu pukul 00:00, jadi hal-hal WEEKDAY menjadi sedikit buruk. Anda benar tentang keterbacaan.
O. Jones
@OllieJones sempurna! Terima kasih banyak!
Joe Cheng
1
Solusi dan artikel hebat. Terima kasih!
Jeremy Wiggins
Ada cara untuk menetapkan "Senin" sebagai hari pertama?
Pedro Joaquín
25

Anda bisa mendapatkan nomor tahun dan minggu gabungan (200945) menggunakan fungsi YEARWEEK () . Jika saya memahami tujuan Anda dengan benar, itu memungkinkan Anda untuk mengelompokkan data multi-tahun Anda.

Jika Anda membutuhkan stempel waktu aktual untuk awal minggu, itu kurang bagus:

DATE_SUB( field, INTERVAL DAYOFWEEK( field ) - 1 DAY )

Untuk pemesanan bulanan, Anda dapat mempertimbangkan fungsi LAST_DAY () - sortir berdasarkan hari terakhir setiap bulan, tetapi itu harus setara dengan mengurutkan berdasarkan hari pertama bulan ... bukankah begitu?

martin clayton
sumber
1
+1 Martin. Duh bagi saya, saya lupa tentang YEARWEEK () ... Saya tidak banyak menggunakannya.
mjv
4

Cukup iklan ini di pilih:

DATE_FORMAT($yourDate, \'%X %V\') as week

Dan

group_by(week);
Xavier
sumber
bagaimana mengelompokkan berdasarkan bulan
Ravi Teja
Itu tidak mengambil data secara terus menerus tetapi hanya untuk satu tanggal tertentu
Chique_Code
2

Jika Anda membutuhkan tanggal "akhir minggu", ini juga akan berfungsi. Ini akan menghitung jumlah rekaman untuk setiap minggu. Contoh: Jika tiga perintah kerja dibuat antara (inklusif) 1/2/2010 dan 1/8/2010 dan 5 dibuat antara (inklusif) 1/9/2010 dan 1/16/2010 ini akan menghasilkan:

3 1/8/2010
5 1/16/2010

Saya harus menggunakan fungsi DATE () ekstra untuk memotong bidang datetime saya.

SELECT COUNT(*), DATE_ADD( DATE(wo.date_created), INTERVAL (7 - DAYOFWEEK( wo.date_created )) DAY) week_ending
FROM work_order wo
GROUP BY week_ending;
Randy
sumber