我的问题:
我有一个MySQL数据库,按时间顺序存储大量的气象数据(每10分钟插入一次新数据).不幸的是,有几次停电,因此缺少某些行.我最近设法从气象站获取了某些备份文件,现在我想使用它们填写缺失的数据.
DB就是这样的结构(例子):
date* the data
2/10/2009 10:00 ...
2/10/2009 10:10 ...
( Missing data!)
2/10/2009 10:40 ...
2/10/2009 10:50 ...
2/10/2009 11:00 ...
...
Run Code Online (Sandbox Code Playgroud)
*= datatime-type,主键
我的想法:
由于备份和数据库位于不同的计算机上并且流量非常慢,我想到了创建一个MySQL查询,该查询在运行时将返回指定时间范围内所有缺失日期的列表.然后,我可以从备份中提取这些日期并将它们插入到数据库中.
问题:
怎么写这样的查询?我没有权限创建任何辅助表.是否可以在指定的时间间隔内制定所有必需日期的"虚拟表",然后在JOIN?中使用它?或者是否有完全不同的命题来解决我的问题?
编辑:是的,时间戳始终采用上面显示的格式(总是10分钟),除了一些只是缺失.
好的,临时表怎么样?是否有一种优雅的方式自动填充时间范围?如果两个脚本试图同时运行,这会导致表格出现问题吗?
select t1.ts as hival, t2.ts as loval
from metdata t1, metdata t2
where t2.ts = (select max(ts) from metdata t3
where t3.ts < t1.ts)
and not timediff(t1.ts, t2.ts) = '00:10:00'
Run Code Online (Sandbox Code Playgroud)
此查询将返回可用于选择缺失数据的对联.对于查询返回的每个对联,丢失的数据将具有hival和loval之间的时间戳.
编辑 - 请检查,克雷格
得到丢失的时间戳 - 这个SQL有点难以阅读,所以我会稍微分解一下.首先,我们需要一种方法来计算给定的低值和高值之间的一系列时间戳值,间隔为10分钟.无法创建表时执行此操作的方法基于以下sql,它将结果集创建从0到9的所有数字.
select d1.* from
(select 1 as digit
union select 2
union select 3
union select 4
union select 5
union select 6
union select 7
union select 8
union select 9
union select 0
) as d1
Run Code Online (Sandbox Code Playgroud)
...现在通过将此表与其自身的副本组合几次意味着我们可以动态生成指定长度的列表
select curdate() +
INTERVAL (d1.digit * 100 + d2.digit * 10 + d3.digit) * 10 MINUTE
as date
from (select 1 as digit
union select 2
union select 3
union select 4
union select 5
union select 6
union select 7
union select 8
union select 9
union select 0
) as d1
join
(select 1 as digit
union select 2
union select 3
union select 4
union select 5
union select 6
union select 7
union select 8
union select 9
union select 0
) as d2
join
(select 1 as digit
union select 2
union select 3
union select 4
union select 5
union select 6
union select 7
union select 8
union select 9
union select 0
) as d3
where (d1.digit * 100 + d2.digit * 10 + d3.digit) between 1 and 42
order by 1
Run Code Online (Sandbox Code Playgroud)
...现在这段sql正在接近我们需要的东西.它有2个输入变量:
...这意味着我们可以使用原始的sql从上面驱动示例,为每个hival lowval对生成一系列时间戳.忍受我,这个sql现在有点长了......
select daterange.loval + INTERVAL (d1.digit * 100 + d2.digit * 10 + d3.digit) * 10 MINUTE as date
from
(select t1.ts as hival, t2.ts as loval
from metdata t1, metdata t2
where t2.ts = (select max(ts) from metdata t3
where t3.ts < t1.ts)
and not timediff(t1.ts, t2.ts) = '00:10:00'
) as daterange
join
(select 1 as digit
union select 2
union select 3
union select 4
union select 5
union select 6
union select 7
union select 8
union select 9
union select 0
) as d1
join
(select 1 as digit
union select 2
union select 3
union select 4
union select 5
union select 6
union select 7
union select 8
union select 9
union select 0
) as d2
join
(select 1 as digit
union select 2
union select 3
union select 4
union select 5
union select 6
union select 7
union select 8
union select 9
union select 0
) as d3
where (d1.digit * 100 + d2.digit * 10 + d3.digit) between 1 and
round((time_to_sec(timediff(hival, loval))-600) /600)
order by 1
Run Code Online (Sandbox Code Playgroud)
...现在有一些史诗sql
注意:使用数字表3次给出一个超过6天的最大差距