用于动态地按报告的时间跨度分组/压缩的SQL

时间:2011-09-01 17:59:03

标签: sql oracle sql-server-2005 sql-server-2008

如何随时间动态压缩/聚合/分组包含事件的表。 我有一张表,其中包含值和发生时间。

这样的事情:

value_col   time_col
3         | 2011-02-16 22:21:05.250
2         | 2011-02-16 21:21:06.170
15        | 2011-02-16 21:21:05.250

我需要从第一行(最新事件)开始按给定时间跨度(例如每小时)汇总值。所以在这个例子中,我希望最终有两行用于每小时聚合。

5
15

因此,如果有新值:

value_col   time_col
6         | 2011-02-16 23:21:05.247
3         | 2011-02-16 22:21:05.250
2         | 2011-02-16 21:21:06.170
15        | 2011-02-16 21:21:05.250

如果我再次运行该查询,我想最终得到:

9
17

更改查询中的时间范围应该很容易。例如压缩过去30秒,过去6小时,过去24小时等等。我怎么能在oracle和MS SQL中做到这一点?

5 个答案:

答案 0 :(得分:1)

感谢之前的回答,我了解了如何满足所有要求。

对于每条记录,我计算与最新记录的时差,以毫秒为单位(或秒,具体取决于分辨率)。然后,我模拟了我目前感兴趣的时间跨度(例如3600秒= 1小时)。 然后我将该值添加到同一记录的time_col并将其添加到该组。

创建表格:

CREATE TABLE [dbo].[test_table](
    [value_col] [int] NOT NULL,
    [time_col] [datetime] NOT NULL
) ON [PRIMARY]
GO
INSERT [dbo].[test_table] ([value_col], [time_col]) VALUES (3, CAST(0x00009E8C01705737 AS DateTime))
INSERT [dbo].[test_table] ([value_col], [time_col]) VALUES (2, CAST(0x00009E8C015FDD8B AS DateTime))
INSERT [dbo].[test_table] ([value_col], [time_col]) VALUES (15, CAST(0x00009E8C015FDC77 AS DateTime))
INSERT [dbo].[test_table] ([value_col], [time_col]) VALUES (6, CAST(0x00009E8C0180D1F6 AS DateTime))

SQL解决方案:

SELECT SUM(value_col) AS s_val, aggregation_time FROM 
 (SELECT value_col, time_col, 
  DATEADD(millisecond,DATEDIFF(millisecond,time_col,(SELECT MAX(time_col) 
  FROM test_table)) % (3600 * 1000), time_col) AS aggregation_time 
 FROM test_table)
GROUP BY aggregation_time
ORDER BY aggregation_time DESC

Oracle解决方案:

SELECT SUM(value_col) as s_val, aggregation_time FROM
 (SELECT value_col, time_col + 
  (MOD(ROUND(((CAST((SELECT MAX(time_col) FROM test_table) AS DATE ) - 
  CAST(time_col AS DATE ))*86400),0),3600))/86400 as aggregation_time
  FROM test_table l)     
GROUP BY aggregation_time
ORDER BY aggregation_time DESC

如果我想在过去2小时内聚合,我只需将3600更改为7200秒。

结果是:

9   2011-02-16 23:21:05.247
17  2011-02-16 22:21:05.247

答案 1 :(得分:0)

 a              b
3  | 2011-02-16 23:21:05.250
2  | 2011-02-16 22:21:05.267
15 | 2011-02-16 22:21:05.155

with tmp as (
  select a, to_char(b, 'YYYYMMDDHH24') h from tab
)
select sum(a), h from tmp group by h
/

答案 2 :(得分:0)

以下是如何按小时汇总的示例:

SELECT TO_CHAR(TRUNC(a.created, 'HH24'), 'DD.MM.YYYY HH24:MI'), COUNT(*)
FROM all_objects a
GROUP BY TRUNC(a.created, 'HH24');

这为您提供了每小时按其创建时间汇总的all_objects对象数。关键是TRUNC(column, 'HH24'),每小时汇总一次数据。

在你的情况下,像这样:

create table t (i int, d date);
insert into t values (3, to_date('2011-02-16 22:21:05', 'YYYY-MM-DD HH24:MI:SS'));
insert into t values (2, to_date('2011-02-16 21:21:05', 'YYYY-MM-DD HH24:MI:SS'));
insert into t values (15, to_date('2011-02-16 21:21:05', 'YYYY-MM-DD HH24:MI:SS'));
commit;
select sum(i), TO_CHAR(TRUNC(t.d, 'HH24'), 'DD.MM.YYYY HH24:MI') from t group by TRUNC(t.d, 'HH24');

答案 3 :(得分:0)

对于SQLServer,您将拥有类似

的内容
SELECT DATEDIFF(hour,b.date_time_col,a.dt), SUM(b.id)
FROM (SELECT MAX(date_time_col) as dt FROM table1)a,  
table1 b
GROUP BY DATEDIFF(hour,b.date_time_col,a.dt)

Oracle没有DATE_DIFF,相当于TRUNC(24*(a.dt-b.date_time_col))

答案 4 :(得分:0)

这是一个Oracle变体,只使用一个表访问。

SQL> create table t (value,mydate)
  2  as
  3  select 3, to_timestamp('2011-02-16 22:21:05.250','yyyy-mm-dd hh24:mi:ss.ff3') from dual union all
  4  select 2, to_timestamp('2011-02-16 21:21:05.267','yyyy-mm-dd hh24:mi:ss.ff3') from dual union all
  5  select 15, to_timestamp('2011-02-16 21:21:05.155','yyyy-mm-dd hh24:mi:ss.ff3') from dual
  6  /

Table created.

下一个查询按小时差异分组,从最近的时间戳开始计算,这似乎是您想要的:

SQL> select sum(value)
  2    from ( select extract(hour from (max(mydate) over () - mydate)) difference_in_hours
  3                , value
  4             from t
  5         )
  6   group by difference_in_hours
  7   order by difference_in_hours
  8  /

SUM(VALUE)
----------
         5
        15

2 rows selected.

但显然你的例子不准确,因为当我从你的例子中添加第四行时,15值距离最近的时间戳超过两个小时,这导致了一个额外的组:

SQL> insert into t values (6,to_timestamp('2011-02-16 23:21:05.249','yyyy-mm-dd hh24:mi:ss.ff3'))
  2  /

1 row created.

SQL> select sum(value)
  2    from ( select extract(hour from (max(mydate) over () - mydate)) difference_in_hours
  3                , value
  4             from t
  5         )
  6   group by difference_in_hours
  7   order by difference_in_hours
  8  /

SUM(VALUE)
----------
         9
         2
        15

3 rows selected.

所以我误解了你的要求,或者你的例子中有错误吗?

的问候,
罗布。