2016-07-28 76 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

这是一个想法。为每一行分配正确的顺序。然后,如果该位置可用,则改为使用该位置。当有关系,首先把position值:

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小提琴似乎并不奏效这些天,但此查询演示结果:

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); 

编辑;

当我写了上面的内容时,我有一个唠叨的问题怀疑。这是一个应该工作的解决方案。这是更复杂的,但它产生正确的数字:

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 

再见, 安杰洛。