假设我有一个包含记录的时间戳列的表,我想仅使用一个查询来计算两个连续记录之间的最小时间差。
也许像一张桌子......
CREATE TABLE `temperatures` (
`temperature` double,
`time` timestamp DEFAULT CURRENT_TIMESTAMP
);
您需要的是分析函数LAG
和MIN
.
它们在 中缺失MySQL
,但可以使用会话变量轻松模拟。
此查询返回连续记录之间的所有差异:
SELECT (temperature - @r) AS diff,
@r := temperature
FROM (
SELECT @r := 0
) vars,
temperatures
ORDER BY
time
这个返回最小的时间差:
SELECT (
SELECT id,
@m := LEAST(@m, TIMEDIFF(time, @r)) AS mindiff,
@r := time
FROM (
SELECT @m := INTERVAL 100 YEAR,
@r := NULL
) vars,
temperatures
ORDER BY
time, id
) qo
WHERE qo.id =
(
SELECT id
FROM temperatures
ORDER BY
time DESC, id DESC
LIMIT 1
)
请参阅我的博客中的这篇文章,了解如何在以下位置模拟分析函数MySQL
:
如果您PRIMARY KEY
向您的表格添加一个(您应该始终这样做!),那么您可以使用更多SQL
-ish 解决方案:
SELECT temperature -
(
SELECT temperature
FROM temperatures ti
WHERE (ti.timestamp, ti.id) < (to.timestamp, to.id)
ORDER BY
ti.timestamp DESC, ti.id DESC
LIMIT 1
)
FROM temperatures to
ORDER BY
to.timestamp, to.id
但是,MySQL
由于存在错误 20111 ,此解决方案效率非常低。
子查询将不使用range
访问路径,尽管它将使用 ( timestamp
, id
) 上的索引进行排序。
这可以通过创建UDF
返回先前温度的 a 来解决,给定当前记录的id
.
有关详细信息,请参阅我的博客中的这篇文章:
如果您不使用任何过滤条件,那么使用会话变量的解决方案将是最有效的,尽管MySQL
具体。
类似的解决方案SQL Server
如下所示:
SELECT temperature -
(
SELECT TOP 1 temperature
FROM temperatures ti
WHERE ti.timestamp < to.timestamp
OR (ti.timestamp = to.timestamp AND ti.id < to.id)
ORDER BY
ti.timestamp DESC, ti.id DESC
)
FROM temperatures to
ORDER BY
to.timestamp, to.id
和
SELECT MIN(mindiff)
FROM (
SELECT timestamp -
(
SELECT TOP 1 timestamp
FROM temperatures ti
WHERE ti.timestamp < to.timestamp
OR (ti.timestamp = to.timestamp AND ti.id < to.id)
ORDER BY
ti.timestamp DESC, ti.id DESC
) AS mindiff
FROM temperatures to
ORDER BY
to.timestamp, to.id
) q
在SQL Server
中,这可以正常工作,前提是您有一个索引(timestamp, id)
(或仅在 上(timestamp)
,如果您PRIMARY KEY
是集群的)
假设时间戳有唯一约束(防止同时有两个记录):
SELECT MIN(timediff(t1.`time`, t2.`time`)) AS delta_t,
FROM temperatures t1 JOIN temperatures t2 ON t1.`time` < t2.`time`
这相当准确地回答了问题 - 并且不传达其他有用的信息(例如哪两个时间戳或温度)。
尝试这样的查询:
select
cur.timestamp as CurrentTime,
prev.timestamp as PreviousTime,
timediff(cur.timestamp,prev.timestamp) as TimeDifference,
cur.temperature - prev.temperature as TemperatureDifference
from temperatures cur
left join temperatures prev on prev.timestamp < cur.timestamp
left join temperatures inbetween
on prev.timestamp < inbetween.timestamp
and inbetween.timestamp < cur.timestamp
where inbetween.timestamp is null
第一个连接查找当前(“cur”)行的所有先前行。第二个连接查找第一行和第二行之间的行。where 语句表示第一行和第二行之间不能有任何行。这样,您将获得包含前一行的行列表。
你可以试试这个:
SELECT
T1.*,
(SELECT MIN(T2.time)
FROM temperatures T2
WHERE T2.time > T1.time)-T1.time diff
FROM
temperatures T1
ORDER BY
T1.time