SQL查询(分钟时间序列数据点)以获取给定小时内的所有数据点加上下一小时的第一个数据点?

SQL查询(分钟时间序列数据点)以获取给定小时内的所有数据点加上下一小时的第一个数据点?,sql,postgresql,date,Sql,Postgresql,Date,我有一个由流id和时间戳键控的数据值表,基本上每一行代表一分钟的数据,给定一个特定的流在特定的分钟,该表有许多流和许多分钟 所以我试图查询一组数据流,一个小时内的任何数据点加上下一个小时按时间顺序排列的第一个数据点,这是我遇到麻烦的部分 它也很难,因为60个1分钟的行中的任何一个都可能丢失,而且我想要单个数据点,即使在中间的时候,只要它是第一个。所以我不能只查询“2019-12-06 00:00:00”-“2019-12-06 01:01:00” 对不起,这可能不清楚,但如果你看看我的例子,我认

我有一个由流id和时间戳键控的数据值表,基本上每一行代表一分钟的数据,给定一个特定的流在特定的分钟,该表有许多流和许多分钟

所以我试图查询一组数据流,一个小时内的任何数据点加上下一个小时按时间顺序排列的第一个数据点,这是我遇到麻烦的部分

它也很难,因为60个1分钟的行中的任何一个都可能丢失,而且我想要单个数据点,即使在中间的时候,只要它是第一个。所以我不能只查询“2019-12-06 00:00:00”-“2019-12-06 01:01:00”

对不起,这可能不清楚,但如果你看看我的例子,我认为这是有意义的

我在测试用例上做了几次尝试,但我感觉它们不是通用的,或者我可以用更好的方法来做

SELECT stream_id, time_stamp, my_data
FROM data_points_minutes
WHERE
  time_stamp >= '2019-12-06 00:00:00'
  AND time_stamp < '2019-12-06 01:00:00'
  AND stream_id IN (123, 456, 789)
UNION
SELECT DISTINCT ON (stream_id) stream_id, time_stamp, my_data
FROM data_point_minutes
WHERE
  time_slot >= '2019-12-06 01:00:00'
  AND time_slot < '2019-12-06 02:00:00'
  AND stream_id IN (123, 456, 789)
ORDER BY
  stream_id, time_stamp;
这适用于我的测试数据,但我担心SELECT DISTINCT仅起作用,因为它们已经按时间戳排序,但如果不按时间戳排序,则不会起作用,这导致我

SELECT *
FROM(
    SELECT stream_id, time_stamp, my_value
    FROM
      data_point_minutes
    WHERE
      time_stamp >= '2019-12-06 00:00:00'
      AND time_stamp < '2019-12-06 01:00:00'
      AND stream_id IN (123, 456, 789)
  ) as q1
UNION
SELECT *
FROM(
    SELECT
      DISTINCT ON (stream_id) stream_id, time_stamp, my_value
    FROM
      data_point_minutes
    WHERE
      time_stamp >= '2019-12-06 01:00:00'
      AND time_stamp < '2019-12-06 02:00:00'
      AND stream_id IN (123, 456, 789)
    ORDER BY
      stream_id, time_stamp ASC
  ) AS q2
ORDER BY
  stream_id, time_stamp;
我认为这基本上是可行的,我可能会这样做,但这种嵌套方式对我来说似乎有点尴尬,所以我希望有人能提出一些更优雅的建议。

您可以在下一个时间戳上使用等式检查来确定日期范围上限的条件,这可以通过子查询来计算:

select stream_id, time_stamp, my_data
from data_points_minutes
where
    stream_id in (123, 456, 789)
    and time_stamp >= '2019-12-06 00:00:00' 
    and (
        time_stamp < '2019-12-06 01:00:00'
        or time_stamp = (
            select min(d1.time_stamp) 
            from data_points_minutes d1
            where d1.stream_id in (123, 456, 789) and d1.timestamp >= '2019-12-06 01:00:00'
        )
    )
select stream_id, time_stamp, my_data
from data_points_minutes d
where
    stream_id in (123, 456, 789)
    and time_stamp >= '2019-12-06 00:00:00' 
    and (
        time_stamp < '2019-12-06 01:00:00'
        or time_stamp = (
            select min(d1.time_stamp) 
            from data_points_minutes d1
            where d1.stream_id = d.stream_id and d1.timestamp >= '2019-12-06 01:00:00'
        )
    )

基本上,您想要的是给定行集合中每个流的时间戳的最小值,从下一个小时和argmin中选择,该行上达到了最小值。有几种方法可以解决这个问题,但最具可读性的方法可能是使用

以下是生成一些测试值的查询:

WITH Data AS (
  select * from (values 
    (NOW()                , 1), 
    (NOW() + interval '1m', 1),   
    (NOW() + interval '1m', 2), 
    (NOW() + interval '2m', 2)
  ) T(ts, stream)
)
SELECT * FROM Data;

              ts               | stream 
-------------------------------+--------
 2019-12-14 01:08:07.556573+00 |      1
 2019-12-14 01:09:07.556573+00 |      1
 2019-12-14 01:09:07.556573+00 |      2
 2019-12-14 01:10:07.556573+00 |      2
计算每个流的最小时间戳及其argmin的查询:

WITH Data AS (
  select * from (values 
    (NOW()                , 1), 
    (NOW() + interval '1m', 1),   
    (NOW() + interval '1m', 2), 
    (NOW() + interval '2m', 2)
  ) T(ts, stream)
),
RankedData AS (
  SELECT ts, 
         RANK() OVER (PARTITION BY stream ORDER BY ts), 
         stream 
  FROM Data
)        
SELECT * FROM RankedData WHERE rank=1;

              ts               | rank | stream 
-------------------------------+------+--------
 2019-12-14 01:12:08.676228+00 |    1 |      1
 2019-12-14 01:13:08.676228+00 |    1 |      2

如果您从下一个小时开始将数据构建为行选择,那么它将解决您的问题:

SELECT stream_id, time_stamp, my_data
FROM data_points_minutes
WHERE
  time_stamp >= '2019-12-06 00:00:00'
  AND time_stamp < '2019-12-06 01:00:00'
  AND stream_id IN (123, 456, 789)
UNION (
WITH Data AS (
SELECT stream_id, time_stamp, my_data
FROM data_point_minutes
WHERE
  time_slot >= '2019-12-06 01:00:00'
  AND time_slot < '2019-12-06 02:00:00'
  AND stream_id IN (123, 456, 789)
),
RankedData AS (
  SELECT time_stamp, my_data 
         RANK() OVER (PARTITION BY stream_id ORDER BY time_stamp), 
         stream_id
  FROM Data
)
SELECT stream_id, time_stamp, my_data FROM RankedData WHERE rank=1
)

感谢您的回复,但我认为问题在于它会在所有流中包含一行最小时间戳,但我想为每个流获得最小时间戳。-编辑抱歉没有看到您的编辑,让我测试一下。@nodsknowly:是的,我怀疑,在您发表评论之前不久,我更新了我的答案。是的,我认为这是同一个问题,我认为这是有意义的,因为子查询使用min,所以它只为所有流返回一个最小值。不过,我喜欢平等使用or的想法,这比使用联合要好得多。我将尝试使用它来解决一些问题。使用distinct on语法表明您似乎在使用postgres。如果是,请删除mysql标记。