按值排序行

时间:2016-07-28 12:59:40

标签: sql postgresql

我按排名尝试订单表,但是具有位置值的行 - 必须根据位置字段中的值来定位。没有额外的表格,视图等可以做到吗?

我有这样的表:

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

2 个答案:

答案 0 :(得分: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 Fiddle这些天似乎没有工作,但是这个查询证明了结果:

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(*)

答案 1 :(得分: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 

再见 安吉洛。