草庐IT

mysql - 在不完全同步时对齐时间戳

coder 2023-10-19 原文

我有 3 个进程 A、B 和 C,如下表系列中所定义:

http://sqlfiddle.com/#!2/48f54

CREATE TABLE processA
(date_time datetime, valueA int);

INSERT INTO processA
                (date_time, valueA)
VALUES
('2013-1-8  22:10:00', 100),
('2013-1-8  22:15:00', 100),
('2013-1-8  22:30:00', 100),
('2013-1-8  22:35:00', 100),
('2013-1-8  22:40:00', 100),
('2013-1-8  22:45:00', 100),
('2013-1-8  22:50:00', 100),
('2013-1-8  23:05:00', 100),
('2013-1-8  23:10:00', 100),
('2013-1-8  23:20:00', 100),
('2013-1-8  23:25:00', 100),
('2013-1-8  23:35:00', 100),
('2013-1-8  23:40:00', 100),
('2013-1-9  00:05:00', 100),
('2013-1-9  00:10:00', 100);


CREATE TABLE processB
(date_time datetime, valueB decimal(4,2));

INSERT INTO processB
                (date_time, valueB)
VALUES
('2013-1-08  21:46:00', 3),
  ('2013-1-08  22:11:00', 4),
  ('2013-1-08  22:31:00', 5),
  ('2013-1-08  22:36:00', 6),
  ('2013-1-08  22:41:00', 7),
  ('2013-1-08  23:06:00', 8),
  ('2013-1-08  23:20:00', 2),
  ('2013-1-08  23:46:00', 3),
  ('2013-1-09  00:34:00', 9);


CREATE TABLE processC
(date_time datetime, status varchar(4));

INSERT INTO processC

VALUES
('2013-1-08 18:00:00', 'yes'),
('2013-1-08 19:00:00', 'yes'),
('2013-1-08 20:00:00', 'yes'),
('2013-1-08 21:00:00', 'yes'),
('2013-1-08 22:00:00', 'yes'),
('2013-1-08 23:00:00', 'no'),
('2013-1-08 00:00:00', 'no'),
('2013-1-08 01:00:00', 'no');

如您所见,每个进程的读数发生时间都不相同。

  1. ProcessA,如果它发生,每隔 5 分钟发生一次

  2. ProcessB,读数发生在不可预测的时间,但通常在一小时内发生多次

  3. ProcessC 始终有一个小时值(是或否)。

首先,我想转换 processB,以便每隔 5 分钟就有一个读数,以便数据与 processA 对齐,这样我就可以在 5 分钟的时间间隔标记处对两个表进行简单的连接。对于转换,每 5 分钟的数据应设置为在 [-30,30) 分钟窗口内可用的最近 processB 观察。如果值是等距的,则取平均值。如果在 30 分钟窗口内没有可用的,则将其设置为空。

一旦我有了它,我就可以使用 ProcessC 在 %Y%m%d%H 上进行简单的连接,使用类似下面的方法来获得所有数据在 5 分钟间隔标记处对齐的最终表:

date_format(date_time, '%Y%m%d%H') = date_format(date_time, '%Y%m%d%H')

如果有人有任何指示/指导,我将不胜感激。我很感激。

示例输出:

'2013-1-8  22:10:00', 100, 4, yes    <--- closer to 22:11 than 21:46
'2013-1-8  22:15:00', 100, 4, yes    <--- closer to 22:11 than 21:31
'2013-1-8  22:30:00', 100, 5, yes    <--- closer to 22:31 than 22:11
'2013-1-8  22:35:00', 100, 6, yes    <--- closer to 22:36 than 22:31
'2013-1-8  22:40:00', 100, 7, yes    <--- closer to 22:41 than 22:36
'2013-1-8  22:45:00', 100, 7, yes    <--- closer to 22:41 than 23:06
'2013-1-8  22:50:00', 100, 7, yes    <--- closer to 22:41 than 23:06
'2013-1-8  23:05:00', 100, 8, yes    <--- closer to 23:06 than 23:06
'2013-1-8  23:10:00', 100, 8, no     <--- closer to 23:06 than 23:20
'2013-1-8  23:20:00', 100, 2, no     <--- closer to 23:20 than 23:10
'2013-1-8  23:25:00', 100, 2, no    <--- closer to 23:20 than 23:10
'2013-1-8  23:35:00', 100, 3, no    <--- closer to 23:46 than 23:20
'2013-1-9  00:05:00', 100, 3, no    <--- closer to 23:46 than 00:34
'2013-1-9  00:10:00', 100, 6, no    <--- takes the avg of 3 and 9

最佳答案

其中棘手的部分是从 processB 中检索适当的一行或多行对应于 processA 的每一行如您所想。

让我们一步一步来。

首先,我们需要能够连接 processA 和 processB 以检索候选时间戳对。让我们这样做:

               SELECT a.date_time a, 
                      TIMESTAMPDIFF(SECOND, a.date_time, b.date_time) timediff
                 FROM processA a
                 JOIN processB b 
                   ON TIMESTAMPDIFF(SECOND, a.date_time, b.date_time) >= -1800
                  AND TIMESTAMPDIFF(SECOND, a.date_time, b.date_time) <   1800

这使我们得到满足 [-30, 30) 标准的 a 和 b 时间。这个结果中有很多行;但我们可以检查它以确保我们正确地完成了范围比较。 http://sqlfiddle.com/#!2/48f54/47/0

现在我们需要生成时间窗口来为您的一个或多个匹配的 b 记录搜索每个 a 记录。就像这样。

       SELECT a, 
              MIN(ABS(timediff)) windowsize
          FROM (
               SELECT a.date_time a, 
                      TIMESTAMPDIFF(SECOND, a.date_time, b.date_time) timediff
                 FROM processA a
                 JOIN processB b 
                   ON TIMESTAMPDIFF(SECOND, a.date_time, b.date_time) >= -1800
                  AND TIMESTAMPDIFF(SECOND, a.date_time, b.date_time) <   1800
         ) d
        GROUP BY a  

这会产生两列:第一列是来自 a 的时间戳,第二列是范围内最近的 b 时间戳(或时间戳,如果要对多个时间戳进行平均)的时间范围。此结果集没有任何记录的行没有足够近的 b 记录来考虑。 http://sqlfiddle.com/#!2/48f54/46/0

最后,我们需要检索每个 a 记录的 b 记录值并求平均值。这是。

SELECT processA.date_time date_time,
       processA.valueA valueA,
       AVG(processB.valueB) valueB
  FROM processA
  LEFT JOIN (
        SELECT a, 
               MIN(ABS(timediff)) windowsize
              FROM (
                   SELECT a.date_time a, 
                          TIMESTAMPDIFF(SECOND, a.date_time, b.date_time) timediff
                     FROM processA a
                     JOIN processB b 
                       ON TIMESTAMPDIFF(SECOND, a.date_time, b.date_time) >= -1800
                      AND TIMESTAMPDIFF(SECOND, a.date_time, b.date_time) <   1800
             ) d
          GROUP BY a
    ) j ON processA.date_time = j.a
   LEFT JOIN processB ON (    processB.date_time >= j.a - INTERVAL j.windowsize SECOND
                          AND processB.date_time <= j.a + INTERVAL j.windowsize SECOND
                          AND processB.date_time < j.a + INTERVAL 1800 SECOND)
  GROUP BY processA.date_time, processA.valueA

注意这里有几个开放范围(< 运算符而不是 <= 运算符)。那些是为了适应你的 [-30, 30) 开放范围。这是查询。 http://sqlfiddle.com/#!2/48f54/45/0

最后一个查询将三个表连接在一起:processA ,我们的虚拟表显示了每个时间戳的搜索范围,以及 process B .最后ON子句执行实际的范围搜索。开放范围使它稍微复杂一些。

看看进展如何?从内到外构建查询很有帮助。

不要忘记在 processB.date_time 上添加索引。

我冒昧地离开了 processC 的连接到这个虚拟表给你。

关于mysql - 在不完全同步时对齐时间戳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17030707/

有关mysql - 在不完全同步时对齐时间戳的更多相关文章

  1. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  2. ruby-on-rails - 将 Ruby 中的日期/时间格式化为 YYYY-MM-DD HH :MM:SS - 2

    这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build

  3. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

  4. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  5. sql - 查询忽略时间戳日期的时间范围 - 2

    我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时

  6. ruby - 在没有基准或时间的情况下用 Ruby 测量用户时间或系统时间 - 2

    因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实

  7. ruby-on-rails - 无法安装 mysql2 0.3.14 gem - 2

    我看到其他人也遇到过类似的问题,但没有一个解决方案对我有用。0.3.14gem与其他gem文件一起存在。我已经完全按照此处指示完成了所有操作:https://github.com/brianmario/mysql2.我仍然得到以下信息。我不知道为什么安装程序指示它找不到include目录,因为我已经检查过它存在。thread.h文件存在,但不在ruby​​目录中。相反,它在这里:C:\RailsInstaller\DevKit\lib\perl5\5.8\msys\CORE\我正在运行Windows7并尝试在Aptana3中构建我的Rails项目。我的Ruby是1.9.3。$gemin

  8. ruby - 以毫秒为单位获取当前系统时间 - 2

    在Ruby中,以毫秒为单位获取自纪元(1970)以来的当前系统时间的正确方法是什么?我试过了Time.now.to_i,好像不是我想要的结果。我需要结果显示毫秒并且使用long类型,而不是float或double。 最佳答案 (Time.now.to_f*1000).to_iTime.now.to_f显示包含十进制数字的时间。要获得毫秒数,只需将时间乘以1000。 关于ruby-以毫秒为单位获取当前系统时间,我们在StackOverflow上找到一个类似的问题:

  9. ruby - 如何使用 ruby​​ mysql2 执行事务 - 2

    我已经开始使用mysql2gem。我试图弄清楚一些基本的事情——其中之一是如何明确地执行事务(对于批处理操作,比如多个INSERT/UPDATE查询)。在旧的ruby-mysql中,这是我的方法:client=Mysql.real_connect(...)inserts=["INSERTINTO...","UPDATE..WHEREid=..",#etc]client.autocommit(false)inserts.eachdo|ins|beginclient.query(ins)rescue#handleerrorsorabortentirelyendendclient.commi

  10. ruby-on-rails - Ruby on Rails - 需要在每周的特定时间将消息发送到电子邮件 - 2

    我想知道我应该如何着手这个项目。我需要每周向人们发送一次电子邮件。但是,这必须在每周的特定时间自动生成并发送。编码有多难?我需要知道是否有任何书籍可以提供帮助,或者你们中的任何人是否可以指导我。它必须使用ruby​​onrails进行编程。因此有一个网络服务和数据库集成。干杯 最佳答案 为什么这么复杂?您只需安排工作。您可以使用Delayed::Job例如。Delayed::Job让您可以使用run_at符号在特定时间安排作业,如下所示:Delayed::Job.enqueue(SendEmailJob.new(...),:run_

随机推荐