PostgreSQL:设置一个列,其中行的序号通过另一个字段排序

时间:2015-01-26 15:34:24

标签: postgresql

我有一个表segnature,用于描述带有varchar字段deno和数字字段ord的项目。外键fk_collection告诉该行是哪一个集合。

我想更新字段ord,以便它包含每个集合的该行的序号,按字段deno排序。

E.g。如果我有类似

的东西
[deno]     ord   [fk_collection]
abc              10
aab              10
bcd              10
zxc              20
vbn              20

然后我想要一个像

这样的结果
[deno]     ord   [fk_collection]
abc          1   10
aab          0   10
bcd          2   10
zxc          1   20
vbn          0   20

我试过像

这样的东西
update segnature s1 set ord = (select count(*) 
    from segnature s2 
    where s1.fk_collection=s2.fk_collection and s2.deno<s1.deno
)

但查询确实速度慢:每10万分左右就会更新每300件商品150件。

有什么建议加快这个过程吗?

谢谢!

1 个答案:

答案 0 :(得分:4)

您可以使用窗口函数生成&#34;序数&#34;号:

with numbered as (
   select deno, fk_collection, 
          row_number() over (partition by fk_collection order by deno) as rn, 
          ctid as id
   from segnature
) 
update segnature
  set ord = n.rn
from numbered n
where n.id = segnature.ctid;

这使用内部列ctid来唯一标识每一行。 ctid比较速度非常慢,因此如果您在该表中有一个真正的主键(或唯一键),请改用该列。

或者没有common table expression

update segnature
  set ord = n.rn
from (
    select deno, fk_collection, 
           row_number() over (partition by fk_collection order by deno) as rn, 
           ctid as id
    from segnature
) as n
where n.id = segnature.ctid;

SQLFiddle示例:http://sqlfiddle.com/#!15/e997f/1