2011-09-28 75 views
2

我有一个包含Y-m-d H:i:s格式的日期时间的created_at列的数据库。每周间隔查询数据库

最新的日期时间条目是2011-09-28 00:10:02

我需要查询相对于最新的日期时间条目。

  1. 查询中的第一个值应该是最新的日期时间条目。
  2. 查询中的第二个值应该是距离第一个值最近7天的条目。
  3. 第三个值应该是距第二个值最近7天的条目。
  4. REPEAT#3。

我所说的“最近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) 
13171| 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 

我希望这更有意义。

回答

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查询,意思是它显示了如上所述的“期间”组的聚合结果 - 而不是像“普通”查询那样逐行结果。使用分组查询,您仅限于使用聚合列。聚合列是那些在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)

+0

这真是太神奇了,真的很感谢你。他们有两个问题,每个查询返回第一个条目(id = 1),但它没有返回最新条目。除此之外,迄今为止这很有效。 – ThomasReggi

+0

@ThomasReggi - 你能更准确地描述问题吗?我不明白你的意思是什么,当你说“它返回每个查询的第一个条目(id = 1),它没有返回最新的条目”。 – Lee

+0

我在问题帖子的底部有更详细的解释。 – ThomasReggi

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) 
+1

我更新了我的问题,为了响应你的答案,包括我的altred查询和版本,它返回的结果。它不缝合工作,至少我希望它的方式。 – ThomasReggi