如何按周分组带有Unix时间戳的行?

时间:2013-06-27 19:55:57

标签: mysql date group-by timestamp

我目前使用以下查询来获取按天分组的数据:

SELECT DATE(from_unixtime(timestampcolumn)) as date, COUNT(*)
FROM db.table
WHERE timestampcolumn BETWEEN :startTime AND :endTime
GROUP BY DATE(from_unixtime(timestampcolumn))
ORDER BY timestampcolumn

DATE()函数返回字符串YYYY-MM-DD,因此上述查询很简单,适用于按天分组数据,但如何修改它以返回按每周分组的数据?


回应乔纳森的回答:

我尝试在SQL Fiddle中创建一个示例,但DATE() SQL函数由于某种原因在SQL Fiddle中不起作用(它在SQL Fiddle中不起作用,但它在我的生活和wamp上都有效)服务器)。

所以这里有一个例子,你可以试试,如果你想:

SETUP:

CREATE TABLE example(id INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), timestamp INT, data INT);

INSERT INTO example (timestamp, data) VALUES (1355400000, 1);
INSERT INTO example (timestamp, data) VALUES (1355659200, 1);
INSERT INTO example (timestamp, data) VALUES (1357694861, 1);
INSERT INTO example (timestamp, data) VALUES (1355918400, 1);
INSERT INTO example (timestamp, data) VALUES (1356955200, 1);
INSERT INTO example (timestamp, data) VALUES (1358510400, 1);
INSERT INTO example (timestamp, data) VALUES (1358769600, 1);
INSERT INTO example (timestamp, data) VALUES (1358769600, 1);
INSERT INTO example (timestamp, data) VALUES (1371824368, 1);
INSERT INTO example (timestamp, data) VALUES (1371833476, 1);
INSERT INTO example (timestamp, data) VALUES (1371840324, 1);
INSERT INTO example (timestamp, data) VALUES (1371850523, 1);
INSERT INTO example (timestamp, data) VALUES (1371863191, 1);
INSERT INTO example (timestamp, data) VALUES (1371865401, 1);
INSERT INTO example (timestamp, data) VALUES (1371872379, 1);
INSERT INTO example (timestamp, data) VALUES (1372006190, 1);
INSERT INTO example (timestamp, data) VALUES (1372051945, 1);
INSERT INTO example (timestamp, data) VALUES (1372189402, 1);
INSERT INTO example (timestamp, data) VALUES (1372207830, 1);
INSERT INTO example (timestamp, data) VALUES (1372229733, 1);
INSERT INTO example (timestamp, data) VALUES (1372350338, 1);
INSERT INTO example (timestamp, data) VALUES (1372358259, 1);

QUERY:

SELECT DATE(from_unixtime(timestamp)) as date, COUNT(*)
FROM example
WHERE timestamp BETWEEN 0 AND 9999999999999999999999999999999
GROUP BY DATE(from_unixtime(timestamp))
ORDER BY timestamp

输出:

2012-12-13  1
2012-12-16  1
2012-12-19  1
2012-12-31  1
2013-01-08  1
2013-01-18  1
2013-01-21  2
2013-06-21  7
2013-06-23  1
2013-06-24  1
2013-06-25  2
2013-06-26  1
2013-06-27  2

现在,将时间戳除以(7 * 24 * 3600)

QUERY:

SELECT DATE(from_unixtime(timestamp / (7 * 24 * 3600))) as date, COUNT(*)
FROM example
WHERE timestamp BETWEEN 0 AND 9999999999999999999999999999999
GROUP BY DATE(from_unixtime(timestamp / (7 * 24 * 3600)))
ORDER BY timestamp

输出:

1969-12-31  22

3 个答案:

答案 0 :(得分:3)

一个基本想法应该是按时间戳的整数值除以一周中的秒数来分组:timestampcolumn / (7 * 24 * 3600)

然后您需要考虑边缘效应和时区:

  • 1970-01-01是在一周的适当日期(这是星期四,所以可能不是)。
  • 当您的特定数据确实开始一周时;是受冬季和夏季时间(标准和夏令时)的影响吗?

您可以通过在分割之前向时间戳列添加适当的值来处理这些问题。最后一个转折:一些系统可能会弥补闰秒。 POSIX没有。你必须决定这对你是否重要。

另一个需要考虑的选择是,是否有办法将日期格式化为周值(例如,2013年第23周的2013-W23等ISO 8601表示法)。然后,您可以按该字符串进行分组。


这就是我的意思:

SELECT timestamp / (7 * 24 * 3600) AS weekno, COUNT(*)
  FROM example
 WHERE timestamp BETWEEN 0 AND 9999999999999999999999999999999
 GROUP BY timestamp / (7 * 24 * 3600)
 ORDER BY weekno

您可能可以使用GROUP BY weekno,或者您可能需要ORDER BY timestamp / (7 * 24 * 3600),但您可以制作周数。如果您还需要生成日期,则使用:

SELECT timestamp / (7 * 24 * 3600) AS weekno,
       DATE(FROM_UNIXTIME((7 * 24 * 3600) * INT(timestamp / (7 * 24 * 3600))))) AS weekstart,
       COUNT(*)
  FROM example
 WHERE timestamp BETWEEN 0 AND 9999999999999999999999999999999
 GROUP BY timestamp / (7 * 24 * 3600)
 ORDER BY weekno

除非您认为一周的第一天并不总是在数据中表示,否则您可能还会MIN(DATE(FROM_UNIXTIME(timestamp)))使用weekstart

答案 1 :(得分:0)

您是否只能使用原始查询并使用WEEK函数而不是DAY()?

GROUP BY WEEK(from_unixtime(timestampcolumn))

答案 2 :(得分:0)

这是一个基于上述建议的经过测试的干净解决方案:

SELECT  WEEK(from_unixtime(timestamp)) AS week_no, 
        date(from_unixtime(timestamp)) as week_start, 
        COUNT(*) as row_count
FROM api_tracker
GROUP BY WEEK(from_unixtime(timestamp))
ORDER BY week_no DESC

SQL响应:

Results

感谢Shane NJonathan Leffler