我有一个难以解决的问题,我想你可以提供帮助。 我有一个包含数百万条记录的表,根据注册表值每隔10分钟精确分组一次,例如:
记录“01 | 2011/01/03 19:18:00.300”它需要计算的时间 记录是19:18:00.300至19:28:00.299。通过这个过程,它会 小组记录01,02,03。
记录“04 | 2011/01/03 19:29:54.289”它需要计算的时间 记录是19:29:54.289至19:39:54.288。通过这个过程,它会 组仅记录04记录。
记录“05 | 2011/01/04 14:43:43.067”,他需要计算的时间 记录是14:43:43.067到14:43:53.066。通过这个过程,它会 小组记录05,06,07。
记录“08 | 2011/01/04 14:57:55.608;”它需要计算的时间 记录是14:57:55.608至15:07:55.607。通过这个过程,它会 小组记录08,09,10,11,12,13,14,15。
输入数据:
ID TS
01 2011/01/03 19:18:00.300
02 2011/01/03 19:18:00.503
03 2011/01/03 19:20:26.335
04 2011/01/03 19:29:54.289
05 2011/01/04 14:43:43.067
06 2011/01/04 14:50:10.727
07 2011/01/04 14:52:26.827
08 2011/01/04 14:57:55.608
09 2011/01/04 14:57:55.718
10 2011/01/04 14:59:13.603
11 2011/01/04 15:00:34.260
12 2011/01/04 15:02:55.687
13 2011/01/04 15:04:51.917
14 2011/01/04 15:06:24.760
15 2011/01/04 15:07:15.378
输出数据:
ID TS Count
01 2011/01/03 19:18:00.300 3
02 2011/01/03 19:29:54.289 1
03 2011/01/04 14:43:43.067 3
04 2011/01/04 14:57:55.608 8
有没有人能解决这个问题? 已经,感谢你的关注。
答案 0 :(得分:2)
我有一张包含数百万条记录的表格 10分钟
tl; dr:对于不耐烦的人,请参阅答案中的最后一个查询,这是真正的解决方案,其他人是如何到达那里的一步一步。另外,all queries + schemas are available at SQLFiddle,对于那些想玩的人来说。
在我看来,针对此类问题的最佳解决方案是将每个时间戳截断为10分钟的开头,例如,让我们尝试进行以下转换(original -> 10 minutes truncated
):
13:10 -> 13:10
13:15 -> 13:10
13:18 -> 13:10
13:20 -> 13:20
...
如果有人想尝试以下查询,您可以创建架构:
CREATE TABLE your_table(tscol timestamptz);
INSERT INTO your_table VALUES
('2011/01/03 19:18:00.300'),
('2011/01/03 19:18:00.503'),
('2011/01/03 19:20:26.335'),
('2011/01/03 19:29:54.289'),
('2011/01/04 14:43:43.067'),
('2011/01/04 14:50:10.727'),
('2011/01/04 14:52:26.827'),
('2011/01/04 14:57:55.608'),
('2011/01/04 14:57:55.718'),
('2011/01/04 14:59:13.603'),
('2011/01/04 15:00:34.260'),
('2011/01/04 15:02:55.687'),
('2011/01/04 15:07:15.378');
因此,为了做到这一点,我们需要了解date_trunc
和date_part
functions (the latter can be invoked by the standard EXTRACT
)以及interval
data type。让我们一步一步地构建解决方案,最后的想法就是拥有这样的东西(现在是伪代码):
SELECT truncate_the_time_by_10_minutes(tscol) AS trunc10, count(*)
FROM your_table
GROUP BY trunc10
ORDER BY trunc10;
现在,如果问题是“按分钟聚合”,那么我们可以简单地将时间戳截断为分钟,这简单意味着将秒和微秒归零,这正是date_trunc('minute', ...)
所做的,所以:
SELECT date_trunc('minute', tscol) AS trunc_minute, count(*)
FROM your_table
GROUP BY trunc_minute
ORDER BY trunc_minute;
可行,但它不是你想要的,date_trun
的下一个功能是'hour'
,它已经失去了我们需要的信息,因此我们需要'minute'
和'hour'
之间的内容。 SELECT tscol, date_trunc('minute', tscol) AS trunc_minute
FROM your_table
ORDER BY tscol;
。让我们看看上面的查询如何使用一些例子:
tscol | trunc_minute
----------------------------+------------------------
2011-01-03 19:18:00.3-02 | 2011-01-03 19:18:00-02
2011-01-03 19:18:00.503-02 | 2011-01-03 19:18:00-02
2011-01-03 19:20:26.335-02 | 2011-01-03 19:20:00-02
2011-01-03 19:29:54.289-02 | 2011-01-03 19:29:00-02
...
返回:
2011-01-03 19:18:00-02
如果您看到EXTRACT(MINUTE FROM tscol)
,现在我们只需要减去8分钟,我们可以这样做:
18
将返回 18 and 10
18 % 10
的模数,所以 8
给我们 8
timestamp[tz]
分钟,但作为整数,并从interval
减去,我们需要8 * interval '1 minute'
,因为整数表示分钟,我们可以这样做: 00:08:00
,这将为我们提供 SELECT
tscol,
date_trunc('minute', tscol) AS trunc_minute,
CAST(EXTRACT(MINUTE FROM tscol) AS integer) % 10 AS min_to_subtract,
(CAST(EXTRACT(MINUTE FROM tscol) AS integer) % 10) * interval '1 minute' AS interval_to_subtract,
date_trunc('minute', tscol) - (CAST(EXTRACT(MINUTE FROM tscol) AS integer) % 10) * interval '1 minute' AS solution
FROM your_table
ORDER BY tscol;
在上一个查询中获得上述3个步骤,我们(我将展示每个列以便更好地理解):
tscol | trunc_minute | min_to_subtract | interval_to_subtract | solution
----------------------------+------------------------+-----------------+----------------------+------------------------
2011-01-03 19:18:00.3-02 | 2011-01-03 19:18:00-02 | 8 | 00:08:00 | 2011-01-03 19:10:00-02
2011-01-03 19:18:00.503-02 | 2011-01-03 19:18:00-02 | 8 | 00:08:00 | 2011-01-03 19:10:00-02
2011-01-03 19:20:26.335-02 | 2011-01-03 19:20:00-02 | 0 | 00:00:00 | 2011-01-03 19:20:00-02
2011-01-03 19:29:54.289-02 | 2011-01-03 19:29:00-02 | 9 | 00:09:00 | 2011-01-03 19:20:00-02
...
返回:
SELECT
date_trunc('minute', tscol) - (CAST(EXTRACT(MINUTE FROM tscol) AS integer) % 10) * interval '1 minute' AS trunc_10_minute,
count(*)
FROM your_table
GROUP BY trunc_10_minute
ORDER BY trunc_10_minute;
现在,最后一列是我们想要的解决方案,时间戳被截断为10分钟组,现在我们可以简单地汇总并获得最终解决方案:
trunc_10_minute | count
------------------------+-------
2011-01-03 19:10:00-02 | 2
2011-01-03 19:20:00-02 | 2
2011-01-04 14:40:00-02 | 1
2011-01-04 14:50:00-02 | 5
2011-01-04 15:00:00-02 | 5
(5 rows)
返回:
insta.controler 'instaCtrl' ($scope, $http), ->
$http.get('http://api.instagram.com/publicapi/oembed/?url=http://instagr.am/p/fA9uwTtkSN/')
.success(data), ->
#done !
.error(e), ->
#nah !
这就是你给出的确切输出,但我相信这是你真正期望的,如果不是这只是一个小调整的问题。
答案 1 :(得分:0)
这可能有点次优,但它确实有效。递归查询检测间隔的开始和停止时间; count(*)标量子查询计算每个区间内的原始记录数。
WITH RECURSIVE rr AS (
SELECT 1::integer AS num
, MIN(tscol) AS starter
, MIN(tscol) + '10 min'::INTERVAL AS stopper
FROM your_table
UNION ALL
SELECT
1+rr.num AS num
, tscol AS starter
, tscol + '10 min'::INTERVAL AS stopper
FROM your_table yt
JOIN rr ON yt.tscol > rr.stopper
AND NOT EXISTS ( SELECT *
FROM your_table nx
WHERE nx.tscol > rr.stopper
AND nx.tscol < yt.tscol
)
)
SELECT num,starter,stopper
, (SELECT COUNT(*) FROM your_table yt
WHERE yt.tscol BETWEEN rr.starter AND rr.stopper
) AS cnt
FROM rr
;