2017-07-19 6 views
0

データの連続した実行を持つテーブルが与えられます:タスクが進行中に常に増加し、次のタスクが開始されるときにゼロにリセットされる数値、最大値データの各実行の?連続したデータの実行のSQL選択

それぞれの連続実行は、行の任意の番号を持つことができ、データの実行がAA「終了」、「開始」と行によってマークされ、例えばデータが

user_id, action, qty, datetime 
1,  start, 0, 2017-01-01 00:00:01 
1,  record, 0, 2017-01-01 00:00:01 
1,  record, 4, 2017-01-01 00:00:02 
1,  record, 5, 2017-01-01 00:00:03 
1,  record, 6, 2017-01-01 00:00:04 
1,  end, 0, 2017-01-01 00:00:04 
1,  start, 0, 2017-01-01 00:00:05 
1,  record, 0, 2017-01-01 00:00:05 
1,  record, 2, 2017-01-01 00:00:06 
1,  record, 3, 2017-01-01 00:00:07 
1,  end, 0, 2017-01-01 00:00:07 
2,  start, 0, 2017-01-01 00:00:08 
2,  record, 0, 2017-01-01 00:00:08 
2,  record, 3, 2017-01-01 00:00:09 
2,  record, 8, 2017-01-01 00:00:10 
2,  end, 0, 2017-01-01 00:00:10 

ように見えるかもしれませんし、その結果は次のようになります各実行の最大値:

user_id, action, qty, datetime 
1,  record, 6, 2017-01-01 00:00:04 
1,  record, 3, 2017-01-01 00:00:07 
2,  record, 8, 2017-01-01 00:00:10  

postgresのSQL構文(9.3)を使用していますか?そのグループのいくつかの種類は、その後、各グループから最大を選択するが、私はグループ化の部分を行う方法が表示されません。

+0

同じuser_idの場合、2つの重複した実行(異なるセッションなど)ができますか? –

+0

1人のユーザーに重複がないため、次回の実行は常に後で開始されます。 –

答えて

1

迅速かつ汚い、と仮定すると実行が重ならない

with bounds as (select starts.rn, starts.datetime as s, ends.datetime as e from 
(select datetime,ROW_NUMBER() OVER() as rn from runs where action = 'start' order by datetime) as starts 
    join 
(select datetime,ROW_NUMBER() OVER() as rn from runs where action = 'end' order by datetime) as ends 
on starts.rn = ends.rn) 
,with_run as (SELECT *, (select rn from bounds where s <= r.datetime and e >= r.datetime) as run 
    from runs as r) 
,max_qty as (
SELECT run,max(qty) as qty 
    from with_run 
GROUP BY run) 
SELECT s.user_id,s.action,s.qty,s.datetime from with_run as s join max_qty as f on s.run = f.run AND s.qty = f.qty; 

- TESTデータ - @Oto Shavadzeが答えを短くすることができ

create table runs (user_id int, action text, qty int, datetime TIMESTAMP); 
insert INTO runs VALUES 
(1,  'start', 0, '2017-01-01 00:00:01') 
,(1,  'record', 0, '2017-01-01 00:00:01') 
,(1,  'record', 4, '2017-01-01 00:00:02') 
,(1,  'record', 5, '2017-01-01 00:00:03') 
,(1,  'record', 6, '2017-01-01 00:00:04') 
,(1,  'end', 0, '2017-01-01 00:00:04') 
,(1,  'start', 0, '2017-01-01 00:00:05') 
,(1,  'record', 0, '2017-01-01 00:00:05') 
,(1,  'record', 2, '2017-01-01 00:00:06') 
,(1,  'record', 3, '2017-01-01 00:00:07') 
,(1,  'end', 0, '2017-01-01 00:00:07') 
,(2,  'start', 0, '2017-01-01 00:00:08') 
,(2,  'record', 0, '2017-01-01 00:00:08') 
,(2,  'record', 3, '2017-01-01 00:00:09') 
,(2,  'record', 8, '2017-01-01 00:00:10') 
,(2,  'end', 0, '2017-01-01 00:00:10'); 

UPDATE

with lookup as (select action,lag(t.*) over(order by datetime, case when action = 'start' then 0 when action = 'record' then 1 else 2 end) as r from runs t) 
select (r::runs).user_id 
     ,(r::runs).action 
     ,(r::runs).qty 
     ,(r::runs).datetime 
from lookup where action = 'end'; 

私はOPが最大限を考慮しているかどうか不明だと思う、l終了前または終了時の最高の数量。

3

1人のユーザーに重複がなく、次回の実行が常に後で開始される場合は、LAG()ウィンドウ機能を使用できます。

with the_table(user_id, action, qty, datetime) as (
    select 1,'start', 0, '2017-01-01 00:00:01'::timestamp union all 
    select 1,'record', 0, '2017-01-01 00:00:01'::timestamp union all 
    select 1,'record', 4, '2017-01-01 00:00:02'::timestamp union all 
    select 1,'record', 5, '2017-01-01 00:00:03'::timestamp union all 
    select 1,'record', 6, '2017-01-01 00:00:04'::timestamp union all 
    select 1,'end', 0, '2017-01-01 00:00:04'::timestamp union all 
    select 1,'start', 0, '2017-01-01 00:00:05'::timestamp union all 
    select 1,'record', 0, '2017-01-01 00:00:05'::timestamp union all 
    select 1,'record', 2, '2017-01-01 00:00:06'::timestamp union all 
    select 1,'record', 3, '2017-01-01 00:00:07'::timestamp union all 
    select 1,'end', 0, '2017-01-01 00:00:07'::timestamp union all 
    select 2,'start', 0, '2017-01-01 00:00:08'::timestamp union all 
    select 2,'record', 0, '2017-01-01 00:00:08'::timestamp union all 
    select 2,'record', 3, '2017-01-01 00:00:09'::timestamp union all 
    select 2,'record', 8, '2017-01-01 00:00:10'::timestamp union all 
    select 2,'end', 0, '2017-01-01 00:00:10'::timestamp 
) 

select n_user_id, n_action, n_qty, n_datetime from (
    select action, 
    lag(user_id) over(partition by user_id order by datetime, case when action = 'start' then 0 when action = 'record' then 1 else 2 end, qty) as n_user_id, 
    lag(action) over(partition by user_id order by datetime, case when action = 'start' then 0 when action = 'record' then 1 else 2 end, qty) as n_action, 
    lag(qty) over(partition by user_id order by datetime, case when action = 'start' then 0 when action = 'record' then 1 else 2 end, qty) as n_qty, 
    lag(datetime) over(partition by user_id order by datetime, case when action = 'start' then 0 when action = 'record' then 1 else 2 end, qty) as n_datetime 
    from the_table 
)t 
where action = 'end' 

一部action = record行がstartend行と同じ日時を持っているので、私はstartが最初であることを明確にすること、ORDER BYCASEを使用し、その後、record、その後endです。

関連する問題