0

私は構造を持つテーブルを持っています:

id, timestamp, deviceId, datatype, measure

列メジャーの値は、データ型の値を表します。たとえば、処理が開始されたとき、データ型は 19 で測定値は 1 です。処理が完了すると、データ型は 19 のままで、値は 0 で、新しい行は同じタイムスタンプ、データ型 54、および値が何らかの値として挿入されます。これは、完了時に、システムが何らかのトリガーを呼び出してこのテーブルを更新していることを意味します。以下のデータ例

1001, 2013-01-02 09:20:00, 501, 19, 1
1005, 2013-01-02 10:00:00, 501, 19, 0
1006, 2013-01-02 10:00:00, 501, 54, 65

1005 と 1006 のタイムスタンプは同じで、1001 のタイムスタンプは常に 1005 のタイムスタンプよりも小さい

1011, 2013-01-02 09:20:00, 601, 19, 1
1015, 2013-01-02 10:00:00, 601, 19, 0
1016, 2013-01-02 10:00:00, 601, 54, 105

1015 と 1016 のタイムスタンプは同じで、1011 のタイムスタンプは常に 1015 のタイムスタンプよりも小さい

1021, 2013-01-02 09:20:00, 701, 19, 1
1022, 2013-01-02 10:00:00, 701, 19, 0
1023, 2013-01-02 10:00:00, 701, 54, 81

1022 と 1023 のタイムスタンプは同じで、1021 のタイムスタンプは常に 1022 のタイムスタンプよりも小さい

この同じプロセスが、複数のデバイスで同時に発生する可能性があります。

ここでの要件は、完了した各トランザクションの開始時刻と終了時刻を次のように見つけることです

1006, 2013-01-02 09:20:00, 2013-01-02 10:20:00, 501, 65
1016, 2013-01-02 09:20:00, 2013-01-02 10:20:00, 601, 105
1023, 2013-01-02 09:20:00, 2013-01-02 10:20:00, 701, 81

私は約 5 年後に SQL クエリを作成しており、完全に立ち往生しています。ポインタ/提案は高く評価されます。

前もって感謝します

4

3 に答える 3

2

SQL フィドル

CREATE TABLE t
        (id int, ts timestamp, deviceId int, datatype int, measure int)
;

INSERT INTO t
        (id, ts, deviceId, datatype, measure)
VALUES
        (1001, '2013-01-02 09:20:00', 501, 19, 1),
        (1005, '2013-01-02 10:00:00', 501, 19, 0),
        (1006, '2013-01-02 10:00:00', 501, 54, 65),
        (1007, '2013-01-02 10:20:00', 501, 19, 1),
        (1008, '2013-01-02 11:00:00', 501, 19, 0),
        (1009, '2013-01-02 11:00:00', 501, 54, 65),
        (1011, '2013-01-02 09:20:00', 601, 19, 1),
        (1015, '2013-01-02 10:00:00', 601, 19, 0),
        (1016, '2013-01-02 10:00:00', 601, 54, 105),
        (1021, '2013-01-02 09:20:00', 701, 19, 1),
        (1022, '2013-01-02 10:00:00', 701, 19, 0),
        (1023, '2013-01-02 10:00:00', 701, 54, 81)
;

with parted as (
    select floor((rn - 1) / 2.0) p, *
    from (
        select
            row_number() over (partition by deviceId order  by ts, datatype) rn,
            id, ts, deviceId, dataType, measure
        from t
        where not(datatype = 19 and measure = 0)
    ) s
)
select
    p1.id, p0.ts "start", p1.ts "end", p1.deviceId, p1.measure
from
    parted p0
    inner join
    parted p1 on
        p0.deviceId = p1.deviceId
        and p0.p = p1.p
        and p0.datatype = 19 and p1.datatype = 54
order by p1.id
;
  id  |        start        |         end         | deviceid | measure 
------+---------------------+---------------------+----------+---------
 1006 | 2013-01-02 09:20:00 | 2013-01-02 10:00:00 |      501 |      65
 1009 | 2013-01-02 10:20:00 | 2013-01-02 11:00:00 |      501 |      65
 1016 | 2013-01-02 09:20:00 | 2013-01-02 10:00:00 |      601 |     105
 1023 | 2013-01-02 09:20:00 | 2013-01-02 10:00:00 |      701 |      81
于 2013-01-02T13:45:48.120 に答える
0

ここで問題を大幅に単純化しすぎている可能性がありますが、データ型54の各レコードについて、データ型が19でメジャーが1のデバイスの前のレコードにアクセスできない理由はわかりません。 :

SELECT  result.ID, 
        result.DeviceID, 
        MAX(start.Timestamp) StartTime, 
        result.Timestamp EndTime, 
        result.Measure
FROM    T result
        INNER JOIN T start
            ON start.DeviceID = result.DeviceID
            AND start.Timestamp < result.Timestamp
            AND start.DataType = 19
            AND start.Measure = 1
WHERE   result.DataType = 54
GROUP BY result.ID, result.DeviceID, result.Timestamp, result.Measure

唯一の本当の違いは、最初から始めて結果に向かって進むことによって問題を解決しようとするのではなく、私は結果から始めて、最初に戻って取り組んだということです。プロセスが同じデバイスに対して同時に実行される場合(つまり、前のトランザクションが終了する前に1つのトランザクションが開始される場合)、これは失敗します。

于 2013-01-02T15:07:23.690 に答える
0

これに対する私のロジックは単純な集計です。ただし、集約キーは、同じデバイス ID を持つデータ型 54 を持つ「次の」レコードです。

この次のレコードを取得するために、where句で相関サブクエリを使用しています。

select next54 as id, MIN(timestamp) as starttime, MAX(timestamp) as endtime, MAX(device_id) as device_id,
       MAX(case when id = next54 then measure end)
from (select t.*,
             (select MIN(id) from t t2 where t2.id >= t.id and t2.datatype = 54 and t2.device_id = t.device_id) as next54
      from t
     ) t
group by next54

残りは集計です。

私は個人的に相関サブクエリの大ファンではないので、ウィンドウ関数 (Oracle では分析関数と呼ばれることもあります) を使用してこれを記述することもできます。

select next54 as id, MIN(timestamp) as starttime, MAX(timestamp) as endtime, MAX(device_id) as device_id,
       MAX(case when id = next54 then measure end)
from (select t.*,
             min(id54) over (partition by device_id order by id desc) as next54
       from (select t.*,
                    (case when datatype = 54 then id end) as id54
             from t
            ) t
     ) t
group by next54

minを含む関数は、「累積」最小値を実行します。order by結果は、相関サブクエリと同じになるはずです。

于 2013-01-02T14:41:22.787 に答える