我的数据库包含created_at
列,其中包含Y-m-d H:i:s
格式的日期时间。
最新的日期时间条目为2011-09-28 00:10:02
。
我需要查询相对于最新的日期时间条目。
我的意思是“最接近7天”:
以下是日期,我希望的间隔是一周,一周的秒数是604800
秒。
第一个值的7天等于1316578202(1317183002-604800)
最接近1316578202(7天)的值是...... 1316571974
unix timestamp | Y-m-d H:i:s
1317183002 | 2011-09-28 00:10:02 -> appear in query (first value)
1317101233 | 2011-09-27 01:27:13
1317009182 | 2011-09-25 23:53:02
1316916554 | 2011-09-24 22:09:14
1316836656 | 2011-09-23 23:57:36
1316745220 | 2011-09-22 22:33:40
1316659915 | 2011-09-21 22:51:55
1316571974 | 2011-09-20 22:26:14 -> closest to 7 days from 1317183002 (first value)
1316499187 | 2011-09-20 02:13:07
1316064243 | 2011-09-15 01:24:03
1315967707 | 2011-09-13 22:35:07 -> closest to 7 days from 1316571974 (second value)
1315881414 | 2011-09-12 22:36:54
1315794048 | 2011-09-11 22:20:48
1315715786 | 2011-09-11 00:36:26
1315622142 | 2011-09-09 22:35:42
我真的很感激任何帮助,我无法通过mysql做到这一点,没有在线资源似乎处理相对日期操作,如此。我希望查询足够模块化,以便能够每周,每月或每年更改间隔。提前谢谢!
回答#1回复:
SELECT
UNIX_TIMESTAMP(created_at)
AS unix_timestamp,
(
SELECT MIN(UNIX_TIMESTAMP(created_at))
FROM my_table
WHERE created_at >=
(
SELECT max(created_at) - 7
FROM my_table
)
)
AS `random_1`,
(
SELECT MIN(UNIX_TIMESTAMP(created_at))
FROM my_table
WHERE created_at >=
(
SELECT MAX(created_at) - 14
FROM my_table
)
)
AS `random_2`
FROM my_table
WHERE created_at =
(
SELECT MAX(created_at)
FROM my_table
)
返回:
unix_timestamp | random_1 | random_2
1317183002 | 1317183002 | 1317183002
回答#2回复:
结果集:
这是每年间隔的结果集:
id | created_at | period_index | period_timestamp
267 | 2010-09-27 22:57:05 | 0 | 1317183002
1 | 2009-12-10 15:08:00 | 1 | 1285554786
我希望这个结果:
id | created_at | period_index | period_timestamp
626 | 2011-09-28 00:10:02 | 0 | 0
267 | 2010-09-27 22:57:05 | 1 | 1317183002
我希望这更有意义。
答案 0 :(得分:1)
这不完全是你所要求的,但下面的例子非常接近......
示例1:
select
floor(timestampdiff(SECOND, tbl.time, most_recent.time)/604800) as period_index,
unix_timestamp(max(tbl.time)) as period_timestamp
from
tbl
, (select max(time) as time from tbl) most_recent
group by period_index
给出结果:
+--------------+------------------+
| period_index | period_timestamp |
+--------------+------------------+
| 0 | 1317183002 |
| 1 | 1316571974 |
| 2 | 1315967707 |
+--------------+------------------+
这会将数据集分为基于“句点”的组,其中(在此示例中)每个句点的长度为7天(604800秒)。每个期间返回的period_timestamp
是该期间内的“最新”(最近)时间戳。
周期边界都是基于数据库中的最新时间戳计算的,而不是根据每个周期的开始和结束时间之前的时间戳计算每个周期的开始和结束时间。差异很微妙 - 你的问题要求后者(迭代方法),但我希望前者(我在这里描述的方法)足以满足你的需求,因为SQL不适合实现迭代算法。
如果您确实需要根据前一时期的时间戳确定每个时段,那么您最好的选择是采用迭代方法 - 使用您选择的编程语言(如php),或者构建使用游标的存储过程。
编辑#1
以下是上述示例的表结构。
CREATE TABLE `tbl` (
`id` int(10) unsigned NOT NULL auto_increment PRIMARY KEY,
`time` datetime NOT NULL
)
编辑#2
好的,首先:我改进了原始示例查询(参见上面修订的“示例1”)。它仍然以相同的方式工作,并给出相同的结果,但它更干净,更有效,更容易理解。
现在......上面的查询是一个分组查询,这意味着它显示了如上所述的“期间”组的聚合结果 - 而不是像“普通”查询那样的逐行结果。使用分组查询,您仅限于使用聚合列。聚合列是在group by
子句中命名的列,或者由MAX(time)
等聚合函数计算的列。无法从分组查询的投影中为非聚合列(如id
)提取有意义的值。
不幸的是,当您尝试执行此操作时,mysql不会生成错误。相反,它只是从分组行中随机选取一个值,并显示分组结果中非聚合列的值。这是导致OP在尝试使用示例#1中的代码时报告的奇怪行为的原因。
幸运的是,这个问题很容易解决。只需围绕组查询包装另一个查询,以选择您感兴趣的逐行信息...
示例2:
SELECT
entries.id,
entries.time,
periods.idx as period_index,
unix_timestamp(periods.time) as period_timestamp
FROM
tbl entries
JOIN
(select
floor(timestampdiff( SECOND, tbl.time, most_recent.time)/31536000) as idx,
max(tbl.time) as time
from
tbl
, (select max(time) as time from tbl) most_recent
group by idx
) periods
ON entries.time = periods.time
结果:
+-----+---------------------+--------------+------------------+
| id | time | period_index | period_timestamp |
+-----+---------------------+--------------+------------------+
| 598 | 2011-09-28 04:10:02 | 0 | 1317183002 |
| 996 | 2010-09-27 22:57:05 | 1 | 1285628225 |
+-----+---------------------+--------------+------------------+
注意:
示例2使用句点长度31536000 seconds
(365天)。而示例1(上面)使用604800 seconds
(7天)的句号。除此之外,示例2中的内部查询与示例1中显示的主查询相同。
如果匹配的period_time属于多个条目(即两个或多个条目具有完全相同的时间,并且该时间与所选的period_time值之一匹配),则上述查询(示例2)将包括给定时间段时间戳的多行(每个匹配一个)。无论代码消耗什么代码,都应准备好处理这样的边缘情况。
值得注意的是,如果在datetime列上定义索引,这些查询的执行效果会更好。对于我的示例模式,它看起来像这样:
ALTER TABLE tbl ADD INDEX idx_time ( time )
答案 1 :(得分:0)
如果你愿意去一周之后的最接近,那么这将是有效的。你可以扩展它以找出最接近的但它看起来很恶心它可能不值得。
select unix_timestamp
, ( select min(unix_tstamp)
from my_table
where sql_tstamp >= ( select max(sql_tstamp) - 7
from my_table )
)
, ( select min(unix_tstamp)
from my_table
where sql_tstamp >= ( select max(sql_tstamp) - 14
from my_table )
)
from my_table
where sql_tstamp = ( select max(sql_tstamp)
from my_table )