MySqlに(timeseries like)テーブルがあり、いくつかのオン/オフイベントを格納しています。これらのイベントはランダムな間隔で報告され、IoTスイッチの現在の状態を表します。
SQLクエリを作成して、スイッチがオンになっていた時間(無制限)を計算する必要があります。
いくつかの障害があります。
[〜#〜] update [〜#〜]私の目標は、特定の期間にスイッチがオンになっていた合計時間を計算することです。例:2018-07-01 00:00:00と2018-07-10 23:59:59の間、スイッチは56分間オンでした。私の考えは、次のような表に「オン」の期間間隔を含めることでした。
date-time | duration-in-munites
2018-07-10 13:47:27 | 47
2018-07-11 00:01:13 | 12
...
日時が最初のONが発生したとき
そこから、特定の期間の期間を合計できます。これは正しい方法ではないかもしれないので、私はそれを行う方法を提案します。
オフからオンへの移行時間と継続時間のみに興味があります
初期値は不明です。スイッチは、「オン」イベントを報告する前に、いくつかの「オフ」イベントを報告した可能性があります
別の問題は、テーブルに他のソースからのデータが含まれているため、IDが連続していないことです。
MySqlサーバーはRaspberry Pi 3で実行されます。私の知る限り、MySQL 8のARMバージョンはありません。
アプローチ1(すべてのバージョンで機能)
ON a.seq = b.seq-1
_を実行して、隣接する行を一致させます。WHERE a.Value != b.Value
_テーブルには、たとえば次のものが含まれます。
_ 3 13:44:13 off 4 13:47:27 on
12 14:27:27 on 13 14:34:48 off
_
thisテーブルの行のペア間のタイムスパンが必要であると仮定して、シーケンス番号を再度追加し、自己結合を実行して、最後から最後までを抽出および減算しますカラム。
アプローチ2(アップグレード用プラグ)
MariaDB 10.2またはMySQL 8.0を使用している場合は、この作業を非常に簡単にする「ウィンドウ関数」があります。 LAG()
を参照してください。自己結合および順序付けの必要がなくなります。
最初のパスでは、_ORDER BY DateTime
_を使用しながらLAG(Value) != Value
を探します。 2番目のパスでは、時間のLAGを現在の時間と比較します。
アプローチ(おそらくウィンドウなしの5.5に最適)
ほぼ旧式の5.5で立ち往生しているので、VIEW
ではなく、ストアドプロシージャの使用を検討してください。 2つの追加のテーブルが含まれます。自己結合に一時テーブルを2回使用することはできないため、これらを_CREATE TEMPORARY TABLE
_にすることはできません。
したがって、より良いアプローチ(ウィンドウ処理なし)は、_@variables
_を使用してLAG()
をシミュレートすることです。
アプローチ4(1と3の間のどこか)
これには、連続する行を確認する単一のパスが含まれます。連続する(日時に基づく)ペアの最初の行がON
である場合、「定刻」を計算します。次にSUM
が「オンタイム」です。
詳細(多分私はあなたに詳細を与えるでしょうが、最初に...)
サンプルデータを提供します(画像ではありません)すぐに実行できます(CREATEs
およびINSERTs
)。期待される出力も提供します。 (私はONからOFFまでを理解していますが、OFFからONについてはどうですか?範囲の開始時間などを希望しますか?)
しゃっくり
「時間通り」に正時で停止したいので、合計などを停止するために追加のコードが必要になります。これを行うための1つの人工的な方法は、毎時0時に1秒間隔で2つの行を追加することです。最初はOFF
、2番目(1秒後)はON
です。これにより、結果に1秒のエラーが発生しますが、「時間帯」要件を単純化することを除いて、アプローチに影響はありません。
ユーザー変数を使用したソリューション:
SELECT p_feed FeedId, MAX(p_start) dt_start, MAX(p_end) dt_end, TIMEDIFF(MAX(p_end), MAX(p_start)) duration
FROM (
SELECT @start := CASE WHEN f.value = 'on' AND @value = 'off' THEN f.`datetime` ELSE null END p_start,
@end := CASE WHEN @value = 'on' AND f.value = 'off' AND @feed = f.FeedId THEN f.`datetime` ELSE null END p_end,
@num := @num + (@start IS NOT NULL) p_num,
@feed := f.FeedId p_feed,
@value := f.value p_value
FROM feedsdata f, (SELECT @start := 0, @end := 0, @num := 0, @feed := 0, @value := '') init_vars
ORDER BY f.FeedId ASC, f.`DateTime` ASC
) subquery
WHERE p_num > 0
GROUP BY p_num
HAVING duration IS NOT NULL;
fiddle (2つの異なるFeedId
値を使用)。
最適化のために(FeedId, `DateTime`)
による索引が必要です。
SELECT FeedId, MIN(dt_start) dt_start, dt_end, TIMEDIFF(dt_end, MIN(dt_start)) duration
FROM ( SELECT t1.FeedId, t1.`DateTime` dt_start, t2.`DateTime` dt_end
FROM feedsdata t1, feedsdata t2
WHERE t1.value = 'on'
AND t2.value = 'off'
AND t1.FeedId = t2.FeedId
AND t1.`DateTime` < t2.`DateTime`
AND NOT EXISTS (SELECT 1
FROM feedsdata
WHERE value = 'off'
AND t1.`DateTime` < `DateTime`
AND `DateTime` < t2.`DateTime`
AND FeedId = t1.FeedId)
) dummy
GROUP BY FeedId, dt_end;