PostgreSQL:设置一列,其中行的序号通过另一个字段排序
PostgreSQL: set a column with the ordinal of the row sorted via another field
我有一个 table segnature
描述了一个带有 varchar 字段 deno
和数字字段 ord
的项目。外键 fk_collection
告诉该行属于哪个集合。
我想更新字段 ord
以便它包含每个集合中该行的序号,按字段 deno 排序。
例如如果我有类似
的东西
[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
)
但查询 确实 很慢:每 30000 个项目中有 150 个集合大约在 10 分钟内更新。
有什么建议可以加快这个过程吗?
谢谢!
您可以使用 window 函数生成 "ordinal" 号码:
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
比较非常慢,因此如果您在 table 中有一个真正的主键(或唯一键),请改用该列。
或者没有 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
我有一个 table segnature
描述了一个带有 varchar 字段 deno
和数字字段 ord
的项目。外键 fk_collection
告诉该行属于哪个集合。
我想更新字段 ord
以便它包含每个集合中该行的序号,按字段 deno 排序。
例如如果我有类似
的东西[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
)
但查询 确实 很慢:每 30000 个项目中有 150 个集合大约在 10 分钟内更新。
有什么建议可以加快这个过程吗?
谢谢!
您可以使用 window 函数生成 "ordinal" 号码:
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
比较非常慢,因此如果您在 table 中有一个真正的主键(或唯一键),请改用该列。
或者没有 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