【问题标题】:MySQL group by week interval on Linux timestamps starting from Sunday从星期日开始的 Linux 时间戳上的 MySQL 组按周间隔
【发布时间】:2020-04-24 11:02:18
【问题描述】:

我有一个已加入的用户表,跟踪他们加入时的时间戳的列是 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

【问题讨论】:

  • 您是否尝试过将时间戳转换为 UTC 日期,然后使用日期函数?
  • @fubar 是的,但是按周分组的日期函数往往会在年底提前结束一周,并不总是在新年伊始的周日开始。
  • 请提供样本数据和预期结果,以便您得到更准确的答案。
  • @GMB 添加了我正在寻找的内容,但成员加入日期可以追溯到几年前

标签: mysql sql date datetime group-by


【解决方案1】:

这就是你想要的。此表达式采用任何 unixtimestamp 值并将其转换为包含您的 unixtimestamp 的星期天午夜的 DATETIME 值。

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

thisthis

作为奖励,这种技术在计算任何 unixtimestamp 的日历周时会尊重您当地的时区。

【讨论】:

  • 谢谢,我会测试一下。无论哪种方式,这些链接都为我提供了非常好的信息,特别是关于调节整周的 YEARWEEK 模组!
  • 我只是遇到与我的 MySQL 版本有关的语法错误...对其进行排序。
  • 我的代码中有几个印刷错误,但我编辑了答案以修复它们。抱歉,请参阅 db-fiddle。
【解决方案2】:

我的代码来自 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 是星期日

下面我将第二个 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>

并获得相同的结果。

顺便说一句,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>

【讨论】:

  • 感谢您的回复,但这是上面答案的副本...您甚至使用了与他相同的 week_beginning(我没有命名)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-27
  • 1970-01-01
  • 2017-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多