2017-10-23 14 views
0

特定のレコードの特定のバージョンに基づいてデータを抽出する必要があります。私はIDの最初のユーザーの最終保存に基づいて最大バージョンを抽出したいと思います。これは可能ですか?
- 私のモックアップでは、バージョン番号は1,2,3ですが、数字は実際にデータベースにランダムに割り当てられています。最大バージョン値を選択

私が使用しようとしています:ここ

select id, max(version) over partition by id 
from t1 

は私のデータです: T1

ID User Version 
1  123  1 
1  123  2 
1  123  3 
1  456  4 
1  456  5 
1  789  6 
2  452  1 
2  452  2 
2  587  3 
2  123  4 
3  901  1 
3  767  2 
3  456  3 

は、ここで私が抽出しようとしているものです: T1

ID User MaxVersion 
1  123  3 
2  452  2 
3  901  1 
+0

ID = 1の場合、Version 1、2、3ではUser = 123、バージョン7ではUser = 123となります(サンプルデータには存在しませんが、ID =ユーザー= 123、バージョン= 7)。その場合、どのバージョンを選択する必要がありますか?3または7?そのユーザーの行が連続していないことに気をつけますか? – mathguy

+0

それはそうではありませんが、それがそうであれば、私の要件は「最初の最終バージョン」を選択することであり、ユーザによるすべての保存は新しいバージョンであり、最後の保存を探していますそのレコードを編集した最初のユーザーの – Skn

+0

OK - Gordonの解決策が役に立たない場合、そのIDを持つCONSECUTIVE行を識別するために余分なレイヤーが必要です。 "それは起こり得ない"が問題ではありませんが、それについては100%確実にする必要があります(現在も将来も!)私が提供したソリューションは、必要なものを提供しますが、Oracle 12.1または高い。あなたのOracleのバージョンは何ですか?確かなことが分からない場合は、 'select * from v $ version'を実行し、完全なバージョン番号(11.2.0.4.0や12.1.0.2.0など)を共有してください。 – mathguy

答えて

2

私はあなたが望むと思う:

select t1.* 
from (select id, 
      row_number() over (partition by id, user order by version desc) as seqnum, 
      max(user) keep (dense_rank first order by version) over (partition by id) as first_user 
     from t1 
    ) t1 
where seqnum = 1 and user = first_user; 

ユーザーと最終レコードを別々に探す必要があります。

EDIT:

あなたが "最初" 最終版が必要な場合は、私は行くだろう:

select t1.* 
from (select t1.*, 
      min(case when user <> first_user then version end) over (partition by id) as last_version_plus_1 
     from (select id, 
        max(user) keep (dense_rank first order by version) over (partition by id) as first_user 
      from t1 
      ) t1 
     where seqnum = 1 and user = first_user 
    ) t1 
where version < max_version; 

それとも、あなたが相関サブクエリでこれを行うことができます。

select t1.* 
from t1 
where t1.user = (select min(tt1.user) keep (dense_rank first order by tt1.version) 
       from t1 tt1 
       where tt1.id = t1.id 
       ) and 
     t1.version < (select min(tt1.version) 
        from t1 tt1 
        where tt1.id = t1.id and tt1.user <> t1.user 
        ); 

この「旧式」アプローチ(事前解析機能)です。しかし、それはまさにその考えを捉えています。最初のユーザーは、ユーザーが最初のユーザーであることを確認します。 2番目のバージョンは、そのユーザーの最初のレコードのバージョンであることを確認します。

+0

ありがとうございました!私は最初のユーザーに行く必要があるので、いくつかの質問があります。パーティションの順序はバージョンascではありませんか?そしてmax(ユーザー) - ユーザーIDが特定の順序にない可能性があるため、ユーザーに対して最大限の操作をしたくありません。 – Skn

+0

'id' **と**' user'(**最高**バージョン番号を取得するために)で分割するときは、降順で並べ替え、行番号を割り当て、行番号= 1を選択する必要があります。 'max(user)'は錯覚です。あなたは 'dense_rank FIRST order by version'を保ち、' version'は 'id'内でユニークなので、' max(user) 'はそのバージョンの** only **ユーザです。私はその質問が100%正しいと信じています.1つの注意点があります。元の投稿の下にある質問を参照してください。 – mathguy

+0

私はこのクエリを実行することができません、エラーが発生しました - 'user'無効な識別子。 – Skn

1

Oracle 12.1以降では、match_recognizeは、このような要件の迅速な作業を行うことができます。 (1つの利点は、解析効率の高いソリューションと比較して、この効率を達成するためにサブクエリを必要とせずに、IDごとにただ1人のユーザーに対してmax(version)が計算されることです)。

idとそれぞれのidの区切りでは、バージョン(昇順)で区切られます。次に、「一致」はパーティションの先頭からのみ(pattern句の^)、最初の行と同じ(idで)idの行のみで構成されます。そのidの他の行はすべて無視されます。その後、最後のバージョン値が出力用に収集されます。

注:これは前提と、その与えられたIDのため、最初のユーザの第二、第三等の変更しかしは最初ユーザ、行のFIRSTセットから最高のバージョン番号に戻る場合そのユーザーのために必要です。そのユーザーのすべての行から最も高いバージョン番号が必要な場合は、それに応じて問合せを変更できます(特にPATTERN句に変更が必要)。

with 
    inputs (id, usr, ver) as ( 
    select 1, 123, 1 from dual union all 
    select 1, 123, 2 from dual union all 
    select 1, 123, 3 from dual union all 
    select 1, 456, 4 from dual union all 
    select 1, 456, 5 from dual union all 
    select 1, 789, 6 from dual union all 
    select 2, 452, 1 from dual union all 
    select 2, 452, 2 from dual union all 
    select 2, 587, 3 from dual union all 
    select 2, 123, 4 from dual union all 
    select 3, 901, 1 from dual union all 
    select 3, 767, 2 from dual union all 
    select 3, 456, 3 from dual 
) 
-- End of simulated inputs (not part of the solution). 
-- SQL query begins BELOW THIS LINE. Use your actual table and column names. 
select id, usr, ver 
from inputs 
match_recognize (
    partition by id 
    order by ver 
    measures last(usr) as usr, 
      last(ver) as ver 
    pattern (^ a+) 
    define a as usr = first(usr) 
); 

ID USR VER 
-- --- --- 
1 123 3 
2 452 2 
3 901 1 

EDIT:完全性については

は、ここでは(たとえ非利用者が非連続した行の上に表示される可能性がある場合のパターンがどのように見えるかで、そのユーザの非常に最後に出現所与id用)の連続が考慮されなければならない:

... 
    pattern (^ a (x* a)?) 
... 

ここパーティション内の最初の行はであり、同じユーザが再び表示された場合同じidの場合、少なくとも1つ以上あります。行です。 最後のこのような行はパターンの任意の部分でキャッチされ、貪欲な一致はx*にあります。

0
select rnk,id, user,mv from (select rownum as rnk,id,user,max(version) from T1 

group by id, user)where rnk=1; 
関連する問題