レコードでいっぱいのタイムスタンプ列を持つテーブルがあり、1 つのクエリのみを使用して、2 つの連続するレコード間の最小時間差を計算したいとします。
みたいなテーブルかも…
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
。
テーブルに a を追加する場合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
ただし、このソリューションは、バグ 20111MySQL
のために非常に非効率的です。
サブクエリはアクセス パスを使用しませんが、順序付けには ( 、 )range
のインデックスを使用します。timestamp
id
UDF
これは、現在のレコードの を指定して、以前の温度を返すを作成することで回避できます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
タイム スタンプに一意の制約があると仮定します (同時に 2 つの録音が行われないようにするため)。
SELECT MIN(timediff(t1.`time`, t2.`time`)) AS delta_t,
FROM temperatures t1 JOIN temperatures t2 ON t1.`time` < t2.`time`
これはかなり正確に質問に答えますが、他の有用な情報 (2 つのタイムスタンプや温度など) は伝えません。
次のようなクエリを試してください。
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") 行の前のすべての行を探します。2 番目の結合は、最初の行と 2 番目の行の間の行を探します。where ステートメントは、最初の行と 2 番目の行の間に行が存在できないことを示しています。そうすれば、前の行を含む行のリストを取得できます。
これを試すことができます:
SELECT
T1.*,
(SELECT MIN(T2.time)
FROM temperatures T2
WHERE T2.time > T1.time)-T1.time diff
FROM
temperatures T1
ORDER BY
T1.time