จะจัดกลุ่มตามสัปดาห์ใน MySQL ได้อย่างไร?


92

เซิร์ฟเวอร์ตารางของ Oracle มีฟังก์ชันในตัว, TRUNC(timestamp,'DY'). ฟังก์ชันนี้จะแปลงการประทับเวลาเป็นเที่ยงคืนของวันอาทิตย์ก่อนหน้า วิธีที่ดีที่สุดในการทำสิ่งนี้ใน MySQL คืออะไร?

Oracle ยังเสนอTRUNC(timestamp,'MM')ให้แปลงการประทับเวลาเป็นเที่ยงคืนในวันแรกของเดือนที่เกิดขึ้น ใน MySQL สิ่งนี้ตรงไปตรงมา:

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

แต่DATE_FORMATเคล็ดลับนี้ใช้ไม่ได้เป็นเวลาหลายสัปดาห์ ฉันทราบถึงWEEK(timestamp)ฟังก์ชันนี้ แต่ฉันไม่ต้องการหมายเลขสัปดาห์ภายในปี สิ่งนี้มีไว้สำหรับการทำงานหลายปี


คุณหมายถึง trunc (sysdate, 'W') ไม่ใช่ trunc (sysdate, 'DY')
David Aldridge

TRUNC(date, 'DY' )ได้รับสัปดาห์โดยเริ่มต้นวันอาทิตย์ 'W'เริ่มต้นวันจันทร์อย่างน้อยก็ในระบบของฉัน
O. Jones

คำตอบ:


123

คุณสามารถใช้ทั้งสองYEAR(timestamp)และWEEK(timestamp)และใช้ทั้งสองนิพจน์เหล่านี้ในSELECTและGROUP BYอนุประโยค

ไม่หรูหราเกินไป แต่ใช้งานได้ ...

และแน่นอนว่าคุณสามารถรวมส่วนวันที่ทั้งสองนี้ไว้ในนิพจน์เดียวได้เช่นกัน

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

แก้ไข : ดังที่มาร์ตินชี้ให้เห็นว่าคุณสามารถใช้YEARWEEK(mysqldatefield)ฟังก์ชันนี้ได้แม้ว่าผลลัพธ์จะไม่เป็นมิตรกับสายตาเหมือนสูตรที่ยาวกว่าข้างต้น


แก้ไข 2 [3 1/2 ปีต่อมา!]:
YEARWEEK(mysqldatefield)ด้วยอาร์กิวเมนต์ที่สองซึ่งเป็นทางเลือก ( mode) ตั้งค่าเป็น 0 หรือ 2 น่าจะเป็นวิธีที่ดีที่สุดในการรวมโดยใช้สัปดาห์ที่สมบูรณ์ (เช่นรวมถึงสัปดาห์ที่คร่อมในวันที่ 1 มกราคม) หากเป็นเช่นนั้น สิ่งที่ต้องการ YEAR() / WEEK()วิธีการที่นำเสนอครั้งแรกในคำตอบนี้มีผลของการแยกข้อมูลที่รวบรวมสำหรับเช่น"คร่อม"ในสัปดาห์ที่สอง: หนึ่งกับปีอดีตเป็นหนึ่งเดียวกับปีใหม่
การทำความสะอาดทุกปีโดยมีค่าใช้จ่ายมากถึงสองสัปดาห์บางส่วนหนึ่งในตอนท้ายมักเป็นที่ต้องการในการบัญชีเป็นต้นและเพื่อให้YEAR() / WEEK()แนวทางนั้นดีกว่า


12
YEARWEEK()ผลลัพธ์INT(6)ที่ฉันเชื่อว่าจะจัดเรียง / เข้าร่วม / กลุ่มได้เร็วขึ้น
KCD

@mjv: จะเกิดอะไรขึ้นเมื่อหุ้นสองปีในสัปดาห์เดียวกัน เช่นวันที่ 31-12-2012 ถึงวันที่ 6-1-2013 (จันทร์ถึงอาทิตย์) มีวิธีแก้ปัญหานี้ไหม
hardik

@hardik: ดูแก้ไข 2 ทั้งนี้ขึ้นอยู่กับความต้องการของคน ๆ หนึ่ง YEARWEEK () อาจเป็นกุญแจสำคัญที่ดีกว่าในการสรุปรวมถ้าเราต้องการทำงานกับสัปดาห์ที่สมบูรณ์แทนที่จะแยกสัปดาห์สุดท้าย / บางส่วนแรกของปี
mjv

@mjv นี่คืออีกวิธีหนึ่งสำหรับลิงค์
hardik

ตรวจสอบให้แน่ใจว่า "การประทับเวลา" ไม่ใช่จำนวนเต็มเหมือนที่ฉันมีในตาราง WEEK (การประทับเวลา) ใช้ประเภทคอลัมน์วันที่ / เวลาประทับเป็นอาร์กิวเมนต์ที่ถูกต้อง
Usman Shaukat

37

คำตอบที่ยอมรับข้างต้นไม่ได้ผลสำหรับฉันเพราะมันเรียงลำดับสัปดาห์ตามลำดับตัวอักษรไม่ใช่ลำดับเวลา:

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

นี่คือวิธีการนับและจัดกลุ่มตามสัปดาห์:

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

สร้าง:

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

5
การสั่งซื้อตามวันที่ ( ORDER BY date ASC) ควรทำเคล็ดลับเช่นกัน
Fender

36

คิดออก ... มันค่อนข้างยุ่งยาก แต่นี่ไง

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

และถ้าหากกฎเกณฑ์ทางธุรกิจของคุณบอกว่าสัปดาห์ที่ผ่านมาของคุณจะเริ่มในวันจันทร์, เปลี่ยนไป-1-2


แก้ไข

หลายปีผ่านไปและในที่สุดฉันก็สามารถเขียนเรื่องนี้ได้ http://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/


@Ollie - ฉันจะพิจารณาใช้ DAYOFWEEK () หรือ WEEKDAY () เพื่อช่วยในการอ่าน
martin Clayton

1
มาร์ตินฉันได้พิจารณาและพบว่าฟังก์ชันเหล่านั้นทำงาน 0-6 สำหรับวันจันทร์ - วันอาทิตย์ กฎทางธุรกิจของฉันบอกว่าสัปดาห์เริ่มต้นในวันอาทิตย์เวลา 00:00 น. ดังนั้นสิ่งต่างๆของ WEEKDAY จึงน่าเกลียดเล็กน้อย คุณพูดถูกเกี่ยวกับความสามารถในการอ่าน
O. Jones

@OllieJones สมบูรณ์แบบ! ขอบคุณมาก!
Joe Cheng

1
ทางออกและบทความที่ยอดเยี่ยม ขอบคุณ!
Jeremy Wiggins

มีวิธีตั้ง "วันจันทร์" เป็นวันกำปั้นไหม?
Pedro Joaquín

25

คุณจะได้รับปีและในสัปดาห์จำนวนตัดแบ่ง (200,945) ใช้yearWeek ()ฟังก์ชั่น หากฉันเข้าใจเป้าหมายของคุณอย่างถูกต้องนั่นจะช่วยให้คุณสามารถจัดกลุ่มข้อมูลหลายปีได้

หากคุณต้องการการประทับเวลาจริงสำหรับการเริ่มต้นสัปดาห์จะดีน้อยกว่า:

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

สำหรับการสั่งซื้อรายเดือนคุณอาจพิจารณาว่าฟังก์ชัน LAST_DAY () - การจัดเรียงจะเป็นวันสุดท้ายของเดือน แต่ควรจะเทียบเท่ากับการจัดเรียงตามวันแรกของเดือน ...


1
+1 มาร์ติน สำหรับฉันฉันลืม YEARWEEK () ... ฉันไม่ได้ใช้มันมากนัก
mjv

4

เพียงโฆษณาสิ่งนี้ในการเลือก:

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

และ

group_by(week);

วิธีจัดกลุ่มตามเดือน
Ravi Teja

ไม่ได้รับข้อมูลอย่างต่อเนื่อง แต่เฉพาะวันที่ระบุวัน
Chique_Code

2

หากคุณต้องการวันที่ "สิ้นสุดสัปดาห์" สิ่งนี้ก็ใช้ได้เช่นกัน การดำเนินการนี้จะนับจำนวนบันทึกในแต่ละสัปดาห์ ตัวอย่าง: หากมีการสร้างใบสั่งงานสามรายการระหว่าง (รวม) 1/2/2010 ถึง 1/8/2010 และ 5 ถูกสร้างขึ้นระหว่าง (รวม) 1/9/2010 และ 1/16/2010 สิ่งนี้จะส่งคืน:

3 1/8/2553
5 1/16/2553

ฉันต้องใช้ฟังก์ชัน DATE () พิเศษเพื่อตัดทอนฟิลด์วันที่และเวลาของฉัน

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;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.