2016-07-28 13 views
1

順位順にテーブルを試していますが、位置値を持つ行は、位置フィールドの値に応じた位置を持つ必要があります。それは追加テーブル、ビューなどなしでそれを行うことは可能ですか?値で行を並べ替える

私はこのような表している:

rank | position | name 
999 | 10  | txt1 
200 | 4  | txt2 
32 | 1  | txt3 
1200 | 2  | txt4 
123 | null  | txt5 
234 | null  | txt6 
567 | null  | txt7 
234 | null  | txt8 
432 | null  | txt9 
877 | null  | txt10 

所望の出力は次のように見ている。ここでは

rank | position | name 
32 | 1  | txt3 
1200 | 2  | txt4 
877 | null  | txt10 
200 | 4  | txt2 
567 | null  | txt7 
432 | null  | txt9 
345 | null  | txt8 
234 | null  | txt6 
123 | null  | txt5  
999 | 10  | txt1 

答えて

6

はアイデアです。各行に適切な順序を割り当てます。次に、位置が利用可能な場合は代わりにそれを使用します。

select t.* 
from (select t.*, row_number() over (order by rank desc) as seqnum 
     from t 
    ) t 
order by (case when position is not null then position else seqnum end), 
     (case when position is not null then 1 else 2 end); 

SQLフィドルは、これらの日に動作していないようですが、このクエリは結果を示しています:絆がある場合は、最初のposition値を入れ

with t(rank, position, t) as (
     select 999, 10, 'txt1' union all 
     select 200, 4, 'txt2' union all 
     select 32 , 1, 'txt3' union all 
     select 1200, 2, 'txt4' union all 
     select 123, null, 'txt5' union all 
     select 234, null, 'txt6' union all 
     select 567, null, 'txt7' union all 
     select 234, null, 'txt8' union all 
     select 432, null, 'txt9' union all 
     select 877, null , 'txt10' 
    ) 
select t.* 
from (select t.*, row_number() over (order by rank desc) as seqnum 
     from t 
    ) t 
order by (case when position is not null then position else seqnum end), 
     (case when position is not null then 1 else 2 end); 

EDITを。

私が上記を書いたとき、私は問題のちょっとした疑いがありました。ここでうまくいくはずの解決策です。それはより複雑ですが、正しい番号を生成します:

with t(rank, position, t) as (
     select 999, 10, 'txt1' union all 
     select 200, 4, 'txt2' union all 
     select 32 , 1, 'txt3' union all 
     select 1200, 2, 'txt4' union all 
     select 123, null, 'txt5' union all 
     select 234, null, 'txt6' union all 
     select 567, null, 'txt7' union all 
     select 234, null, 'txt8' union all 
     select 432, null, 'txt9' union all 
     select 877, null , 'txt10' 
    ) 
select * 
from (select t.*, g.*, 
      row_number() over (partition by t.position order by t.rank) gnum 
     from generate_series(1, 10) g(n) left join 
      t 
      on t.position = g.n 
    ) tg left join 
    (select t.*, 
      row_number() over (partition by t.position order by t.rank) as tnum 
     from t 
    ) t 
    on tg.gnum = t.tnum and t.position is null 
order by n; 

これは奇妙なインターリーブ問題です。アイデアは、位置を生成するためにスロットを生成することです(生成系列を使用します)。次に、既知の位置をスロットに割り当てます。最後に残りのスロットを列挙し、そこに値を割り当てます。

注:10をハードコーディングしましたが、そこからテーブルのcount(*)に入れるのは簡単です。

+0

これは解決策ですが、バグがあります。ランクを変更すると、たとえば大きな番号の最後の行(1234134)に表示されます – Nikitka

0

table1にデータを格納したとします。

update a 
set position = x.pos_null 
from table1 
    a 
inner join 
    (
    select 
     a.name, 
     COUNT(a.rank) as pos_null 
    from 
     (
     select 
      * 
     from table1 
     where position is null 
     ) 
     a 
    left join 
     (
     select 
      *  
     from table1 
     ) 
     b 
     on a.rank <= b.rank 
    group by 
     a.name 
    ) 
    x 
    on a.name = x.name 


select * from table1 order by position 

さようなら、 アンジェロを次のように はその後、列「位置」を更新する必要があります。

関連する問題