用于在组内创建升序值的SQL查询

时间:2016-02-13 18:58:49

标签: sql postgresql sql-update

我有下表:

+----+--------+-----+
| 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_didpos
  • 组合 每个pos
  • fk_did必须提升
  • 如果有一行pos> 0,还必须有一行具有相同的fk_did和一个较低的pos

这可以通过一次更新查询完成吗?

3 个答案:

答案 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开始的序列号。

Demo here

答案 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

然后截断当前表并从临时表中插入记录