【问题标题】:Interpolate Multiseries Data In SQL在 SQL 中插入多序列数据
【发布时间】:2022-01-20 09:47:20
【问题描述】:

我有一个系统,仅在数据更改时才存储数据。因此,数据集如下所示。

data_type_id data_value inserted_at
2 240 2022-01-19 17:20:52
1 30 2022-01-19 17:20:47
2 239 2022-01-19 17:20:42
1 29 2022-01-19 17:20:42

我的数据频率是每 5 秒一次。所以,不管有没有timestamp,我都需要通过假设这个第5秒的数据值与之前的值相同来得到结果。

由于我正在存储仅更改的数据,因此数据集确实应该如下所示。

data_type_id data_value inserted_at
2 240 2022-01-19 17:20:52
1 30 2022-01-19 17:20:52
2 239 2022-01-19 17:20:47
1 30 2022-01-19 17:20:47
2 239 2022-01-19 17:20:42
1 29 2022-01-19 17:20:42

我不想insert into我的表,我只想在SELECT语句中检索这样的数据。

有什么方法可以创建这个查询吗?

PS。我有很多data_types,因此当 OP 进行查询时,它通常会获得大约一百万行。

编辑: 服务器信息Server version: 10.3.27-MariaDB-0+deb10u1 Debian 10

用户将确定SELECT日期时间。所以,没有确定的between 时间。

正如@Akina 提到的,有时inserted_at 之间存在一些差距。差异可能是 ~4 秒或 ~6 秒,而不是特定的 5 秒。由于不会如此频繁地发生,因此可以忽略这一事实来生成。

【问题讨论】:

  • 有什么方法可以创建这个查询吗? 当然可以。提供准确的 MySQL 版本信息。
  • 如何确定所需的日期时间范围?必须从什么日期时间值到什么日期时间值生成表?如果某个间隙不是 N*5 秒(例如由于时间检测精度)怎么办?
  • @Akina 我根据你的问题编辑了问题。
  • 您的版本没有回答“如何确定所需的日期时间范围?”的问题。您告诉“用户将确定 SELECT DateTime”。 - 这是否意味着用户有一个确定的日期时间值并且需要确定此时的值?
  • @Akina 感谢您的回答。用户绘制响应此查询的图表。因此,用户可以绘制3天或1周或2小时或3个月等的图表。他们可以根据自己的喜好确定date_time。因此,您可以考虑在 存储过程 中解决问题,该存储过程以 data_type_idsstart_datetimeend_datetime 作为 IN 参数。

标签: mysql sql interpolation missing-data


【解决方案1】:

借助可获取data_type_id 的所有组合以及所需的 5 秒时刻的查询,您可以使用可获取最接近 data_value 的子查询来获得所需的结果:

with recursive u as
(select '2022-01-19 17:20:42' as d
union all
select DATE_ADD(d, interval 5 second) from u
where d < '2022-01-19 17:20:52'),
v as
(select * from u cross join (select distinct data_type_id from table_name) t)
select v.data_type_id, 
(select data_value from table_name where inserted_at <= d and data_type_id = v.data_type_id
order by inserted_at desc limit 1) as data_value, 
d as inserted_at
from v

Fiddle

您可以将递归 CTE 替换为任何查询,以获得所需的所有 5 秒时刻。

【讨论】:

    【解决方案2】:
    WITH RECURSIVE
    cte1 AS ( SELECT @start_datetime dt
              UNION ALL
              SELECT dt + INTERVAL 5 SECOND FROM cte1 WHERE dt < @end_datetime),
    cte2 AS ( SELECT *,
                     ROW_NUMBER() OVER (PARTITION BY test.data_type_id, cte1.dt
                                        ORDER BY test.inserted_at DESC) rn
              FROM cte1
              LEFT JOIN test ON FIND_IN_SET(test.data_type_id, @data_type_ids) 
                            AND cte1.dt >= test.inserted_at )
    SELECT * 
    FROM cte2
    WHERE rn = 1
    

    https://dbfiddle.uk/?rdbms=mariadb_10.3&fiddle=380ad334de0c980a0ddf1b49bb6fa38e

    【讨论】:

    • 这个解决方案有两个问题。 1.) 尽管2022-01-19 17:20:32 上有数据,但它会为2022-01-19 17:20:35 创建一个时间戳,这使得解决方案更难找到准确的时间。 2.) 我看到,当我删除 WHERE rn = 1 语句时,它会在很短的时间内创建很多额外的行。在寻找最近的timepoint 的情况下看起来非常昂贵。我将尝试调整以解决此问题,因为如果查询一天或更长时间,则需要很长时间...
    • @TaylanYuksel (1) 我不明白你在说什么。您的样本数据不包含指定的值。编辑小提琴数据,重现您的问题,提供链接。 (2) 在 cte2 的 ON 子句中添加相应的条件,将行限制在某个时间范围内,该时间范围超出最大值。与保证的可能差距(例如,5 分钟)。
    • 对于第一点,我知道那是我的错,我意识到没关系。对于第二点,我通过将行限制在某个时间范围内来应用您的建议。它变得更快并且创建的更少rn。但是查询速度对于这个问题来说并不方便。另一个答案更快。我也赞成你的有用答案。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2020-06-16
    • 2017-04-27
    • 2013-03-19
    • 1970-01-01
    • 2016-10-04
    • 2019-08-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多