我有下表:
+----+--------+-----+
| id | fk_did | pos |
+----+--------+-----+
此表包含数百行,每行都引用另一个带fk_did
的表。 pos
中的值当前始终为零,我想要更改。
基本上,对于每个fk_did
组,pos
- 列应从零开始并升序。行如何排序并不重要。
我想得到的示例输出(select * from table order by fk_did, pos
):
+----+--------+-----+
| id | fk_did | pos |
+----+--------+-----+
| xx | 0 | 0 |
| xx | 0 | 1 |
| xx | 0 | 2 |
| xx | 1 | 0 |
| xx | 1 | 1 |
| xx | 1 | 2 |
| xx | 4 | 0 |
| xx | 8 | 0 |
| xx | 8 | 1 |
| xx | 8 | 2 |
+----+--------+-----+
fk_did
和pos
pos
fk_did
必须提升
pos
> 0,还必须有一行具有相同的fk_did
和一个较低的pos
。这可以通过一次更新查询完成吗?
答案 0 :(得分:2)
您可以使用窗口功能执行此操作:
update the_table
set pos = t.rn - 1
from (
select id,
row_number() over (partition by fk_id) as rn
from the_table
) t
where t.id = the_table.id;
pos
的排序或多或少是随机的,因为没有order by
,但你说这没关系。
这假设id
是唯一的,如果不是,您可以使用内部列ctid
。
答案 1 :(得分:1)
如果id
是您的表格的PK,那么您可以使用以下查询来更新您的表格:
UPDATE mytable
SET pos = t.rn
FROM (
SELECT id, fk_did, pos,
ROW_NUMBER() OVER (PARTITION BY fk_did ORDER BY id) - 1 AS rn
FROM mytable) AS t
WHERE mytable.id = t.id
与ROW_NUMBER
子句一起使用的 PARTITION BY
窗口函数为每个fk_did
切片生成从1开始的序列号。
答案 2 :(得分:0)
如果id
列不唯一,我建议创建一个临时表:
create temp table tmp_table as
select id, fk_did, row_number() over (partition by fk_did) - 1 pos
from table_name
然后截断当前表并从临时表中插入记录