MySQL จัดกลุ่มตามช่วงเวลาสัปดาห์บนการประทับเวลา Linux เริ่มตั้งแต่วันอาทิตย์

ฉันมีตารางของผู้ใช้ที่ได้เข้าร่วม และคอลัมน์ที่ติดตามการประทับเวลาเมื่อพวกเขาเข้าร่วมคือการประทับเวลา UNIX

ฉันต้องการจัดกลุ่มพวกมันตามเวลาหนึ่งสัปดาห์ในหน่วยวินาที 604800 แต่กลับเจอสิ่งกีดขวางบนถนน การค้นหาอื่นๆ ใช้สัปดาห์ MySQL แต่นั่นไม่ใช่สิ่งที่ฉันค้นหา เนื่องจากสัปดาห์เหล่านั้นไม่ได้เต็มเสมอไปในช่วงปลายปี และจะแตกต่างกันไปขึ้นอยู่กับวันเริ่มต้น

แบบสอบถามสำหรับการจัดกลุ่มสัปดาห์:

SELECT 
    COUNT(member_id) as new_members,
    MAX(joined) as last_joined,
    MIN(joined) as first_joined,
    YEAR(FROM_UNIXTIME(joined)) AS yr,
    MONTH(FROM_UNIXTIME(joined)) AS mn,
    WEEK(FROM_UNIXTIME(joined)) AS wk
FROM members
WHERE member_group_id NOT IN (2, 4, 7) 
GROUP BY `yr`,`mn`,`wk`
ORDER BY new_members DESC

ฉันต้องการจัดกลุ่มผู้ใช้ของฉันตามการประทับเวลาเริ่มตั้งแต่วันอาทิตย์หน้าลงไป ดังนั้น มันจะเป็นวันอาทิตย์ถัดไป และย้อนกลับไปหนึ่งสัปดาห์จนกว่าฉันจะหมดบันทึก

ฉันได้พยายาม FLOOR( joined / 604800 ) AS weekno แล้ว แต่นั่นไม่ถูกต้องเนื่องจากเริ่มต้นจากบันทึกแรกสุดหรือล่าสุด และฉันต้องการสัปดาห์ที่จะเริ่มต้นในวันอาทิตย์ เช่น:

SELECT COUNT(member_id) as new_members, 
       MAX(joined) as last_joined, MIN(joined) as first_joined, 
       FLOOR( joined / 604800 ) AS weekno 
FROM `members` 
WHERE member_group_id NOT IN (2, 4, 7) 
GROUP BY `weekno` 
ORDER BY weekno DESC

ใครมีเคล็ดลับบ้างไหม?

ข้อมูลตัวอย่างที่ฉันกำลังมองหา

member_id | joined
1         | 1578182420
2         | 1578182430
3         | 1578182500
4         | 1578183400
5         | 1576082400
6         | 1576082410
7         | 1576082420

ผลลัพธ์:

new_members | last_joined | first_joined | week_start
4           | 1578183400  | 1578181400   | 1578182400
3           | 1576082420  | 1576082400   | 1577577600

person Ice76    schedule 06.01.2020    source แหล่งที่มา
comment
คุณได้ลองแปลงการประทับเวลาเป็นวันที่ UTC แล้วใช้ฟังก์ชันวันที่หรือไม่   -  person fubar    schedule 07.01.2020
comment
@fubar ใช่ แต่ฟังก์ชั่นวันที่ที่จัดกลุ่มตามสัปดาห์มีแนวโน้มที่จะสิ้นสุดสัปดาห์ก่อนช่วงสิ้นปีและไม่ได้เริ่มในวันอาทิตย์ในช่วงต้นปีใหม่เสมอไป   -  person Ice76    schedule 07.01.2020
comment
โปรดให้ข้อมูลตัวอย่างและผลลัพธ์ที่คาดหวังเพื่อให้คุณได้รับคำตอบที่แม่นยำยิ่งขึ้น   -  person GMB    schedule 07.01.2020
comment
@GMB เพิ่มสิ่งที่ฉันกำลังมองหา แต่สมาชิกที่เข้าร่วมวันที่ย้อนหลังไปหลายปี   -  person Ice76    schedule 07.01.2020


คำตอบ (2)


นี่คือสิ่งที่คุณต้องการ นิพจน์นี้ใช้ค่า Unixtimestamp ใดๆ และแปลงเป็นค่า DATETIME ซึ่งเป็นเวลาเที่ยงคืนของวันอาทิตย์ในสัปดาห์ที่มีการประทับเวลา Unixtimestamp ของคุณ

FROM_DAYS(TO_DAYS(FROM_UNIXTIME(unixtimestamp)) - 
      MOD(TO_DAYS(FROM_UNIXTIME(unixtimestamp)) -1, 7))

ดังนั้นแบบสอบถามนี้ควรทำเคล็ดลับสำหรับคุณ

SELECT COUNT(member_id) as new_members,
       MAX(joined) as last_joined,
       MIN(joined) as first_joined,
       FROM_DAYS(TO_DAYS(FROM_UNIXTIME(joined)) - 
             MOD(TO_DAYS(FROM_UNIXTIME(joined)) -1, 7) week_beginning
  FROM members
 WHERE member_group_id NOT IN (2, 4, 7) 
 GROUP BY FROM_DAYS(TO_DAYS(FROM_UNIXTIME(joined)) - 
             MOD(TO_DAYS(FROM_UNIXTIME(joined)) -1, 7)
 ORDER BY new_members DESC

ฉันชอบใช้ฟังก์ชันที่เก็บไว้นี้เพื่อจุดประสงค์ การเขียนและอ่านข้อความค้นหาของคุณง่ายกว่าเมื่อคุณใช้งาน

DELIMITER $$
DROP FUNCTION IF EXISTS TRUNC_SUNDAY$$
CREATE
  FUNCTION TRUNC_SUNDAY(datestamp DATETIME)
  RETURNS DATE DETERMINISTIC NO SQL
  COMMENT 'returns preceding Sunday'
  RETURN FROM_DAYS(TO_DAYS(datestamp) -MOD(TO_DAYS(datestamp) -1, 7))$$

หากคุณใช้ฟังก์ชันที่เก็บไว้ คุณสามารถเขียนคำค้นหาของคุณได้ดังนี้ (https://www.db-fiddle.com/f/cbtf9rueAvtFNUxE1PS387/0)

SELECT COUNT(member_id) as new_members,
       MAX(joined) as last_joined,
       MIN(joined) as first_joined,
       TRUNC_SUNDAY(FROM_UNIXTIME(joined)) week_beginning
  FROM members
 GROUP BY TRUNC_SUNDAY(FROM_UNIXTIME(joined))
 ORDER BY new_members DESC

หากคุณต้องการให้สัปดาห์ของคุณเริ่มต้นในวันจันทร์ ให้ใช้ -2 แทน -1 ในนิพจน์

ดูสิ่งนี้ และ สิ่งนี้

โบนัสพิเศษคือ เทคนิคนี้จะยึดตามเขตเวลาท้องถิ่นของคุณเมื่อค้นหาสัปดาห์ปฏิทินของการประทับเวลายูนิกซ์ใดๆ

person O. Jones    schedule 06.01.2020
comment
ขอบคุณครับ จะทดสอบเรื่องนี้ครับ ไม่ว่าจะด้วยวิธีใด ลิงก์เหล่านี้ให้ข้อมูลที่ดีมากแก่ฉัน โดยเฉพาะเกี่ยวกับ YEARWEEK mod ที่ควบคุมทั้งสัปดาห์! - person Ice76; 07.01.2020
comment
ฉันเพิ่งได้รับข้อผิดพลาดทางไวยากรณ์เกี่ยวกับเวอร์ชัน MySQL ของฉัน... กำลังเรียงลำดับตามนั้น - person Ice76; 07.01.2020
comment
ฉันมีข้อผิดพลาดในการพิมพ์สองสามข้อในโค้ดของฉัน แต่ฉันแก้ไขคำตอบเพื่อแก้ไข ขออภัยเกี่ยวกับเรื่องนั้น ดู db-fiddle - person O. Jones; 07.01.2020

รหัสของฉันมาจาก O. Jones ด้านล่างคือสิ่งที่ฉันลอง:

mysql> SELECT COUNT(member_id) as new_members,
    ->        MAX(joined) as last_joined,
    ->        MIN(joined) as first_joined,
    ->        FROM_DAYS(TO_DAYS(FROM_UNIXTIME(joined)) - MOD(TO_DAYS(FROM_UNIXTI
ME(joined)) -1, 7)) as week_beginning
    ->   FROM members
    ->  GROUP BY FROM_DAYS(TO_DAYS(FROM_UNIXTIME(joined)) - MOD(TO_DAYS(FROM_UNI
XTIME(joined)) -1, 7))
    ->  ORDER BY new_members DESC
    -> ;
+-------------+-------------+--------------+----------------+
| new_members | last_joined | first_joined | week_beginning |
+-------------+-------------+--------------+----------------+
|           4 |  1578183400 |   1578182420 | 2020-01-05     |
|           3 |  1576082420 |   1576082400 | 2019-12-08     |
+-------------+-------------+--------------+----------------+
2 rows in set (0.07 sec)

2020-01-05 และ 2020-01-05 เป็นวันอาทิตย์

ด้านล่างฉันแทนที่ 2nd to_days() ด้วย weekday():

mysql> SELECT COUNT(member_id) as new_members,
    -> MAX(joined) as last_joined,
    -> MIN(joined) as first_joined,
    -> FROM_DAYS(TO_DAYS(FROM_UNIXTIME(joined)) - MOD(WEEKDAY(FROM_UNIXTIME(join
ed))+1,7)) as week_beginning
    -> FROM members
    -> GROUP BY FROM_DAYS(TO_DAYS(FROM_UNIXTIME(joined)) - MOD(WEEKDAY(FROM_UNIX
TIME(joined))+1,7))
    -> ORDER BY new_members DESC
    ->
    -> ;
+-------------+-------------+--------------+----------------+
| new_members | last_joined | first_joined | week_beginning |
+-------------+-------------+--------------+----------------+
|           4 |  1578183400 |   1578182420 | 2020-01-05     |
|           3 |  1576082420 |   1576082400 | 2019-12-08     |
+-------------+-------------+--------------+----------------+
2 rows in set (0.00 sec)

mysql>

และได้รับผลลัพธ์เดียวกัน

BTW,weekday() เริ่มตั้งแต่วันจันทร์:

Monday    -> 0
Tuesday   -> 1
Wednesday -> 2
Thursday  -> 3
Friday    -> 4
Saturday  -> 5
Sunday    -> 6

to_days() เริ่มตั้งแต่วันเสาร์ ด้านล่างพิสูจน์ได้:

mysql> select to_days('2020-1-4');
+---------------------+
| to_days('2020-1-4') |
+---------------------+
|              737793 |
+---------------------+
1 row in set (0.00 sec)

mysql> select mod(to_days('2020-1-4'),7);
+----------------------------+
| mod(to_days('2020-1-4'),7) |
+----------------------------+
|                          0 |
+----------------------------+
1 row in set (0.00 sec)

mysql>
person MLKu    schedule 07.01.2020
comment
ขอบคุณสำหรับคำตอบ แต่นี่คือสำเนาของคำตอบด้านบน... คุณยังใช้ week_beginning แบบเดียวกับที่เขาทำ (ซึ่งฉันไม่ได้ตั้งชื่อ) - person Ice76; 07.01.2020