はアイデアです。各行に適切な順序を割り当てます。次に、位置が利用可能な場合は代わりにそれを使用します。
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(*)
に入れるのは簡単です。
これは解決策ですが、バグがあります。ランクを変更すると、たとえば大きな番号の最後の行(1234134)に表示されます – Nikitka