Postgres消除行号中的空白

时间:2019-11-08 18:23:00

标签: sql postgresql

我有一个名为assignment的表,其中包含indexunit_id列。一个单元中的每个作业都有一个唯一的索引。这样,单元中的分配可以通过交换索引来重新排序。

我正在尝试找出消除索引中潜在差距的最佳方法(例如,如果删除一行,索引将进入013 )。我当前的解决方案是以编程方式遍历单元中的每个分配,并在其索引与循环索引不匹配的情况下运行UPDATE查询。像这样:

let i = 0;
for (const assignmentId of assignmentIds) {
  await Assignment.query()
    .patch({ index: i })
    .where('id', assignmentId);
  i++;
}

我正在尝试找出如何使用ROW_NUMBER这样的单个查询来做到这一点:

UPDATE assignment SET
  index = subquery.new_index - 1
FROM (
  SELECT 
    ROW_NUMBER() OVER () as new_index 
  FROM assignment 
  WHERE assignment.unit_id = 35 
  ORDER BY assignment.index
) as subquery 
WHERE unit_id=35;

但是当我运行它时,它只是将单元35中的所有索引设置为1。为什么会这样?

4 个答案:

答案 0 :(得分:1)

您需要在PK列上加入子查询(您需要将其包括在子查询中才能执行此操作)。 order by需要进入窗口功能,而不是整个查询:

UPDATE assignment 
 SET index = subquery.new_index - 1
FROM (
  SELECT pk_column, 
         ROW_NUMBER() OVER (partition by unit_id order by index) as new_index 
  FROM assignment 
) as subquery 
WHERE subquery.pk_column = assignment.pk_column

如果只想对单个单元执行此操作,则可以将AND unit_id = 35添加到UPDATE语句的WHERE子句中。

答案 1 :(得分:1)

您需要通过按旧索引标识行来为每行提供一个新索引:

{'key1', 'key2', 'key3'} >= {'key1', 'key2'}

答案 2 :(得分:0)

如果您不介意原始索引,则可以使用临时序列运行更新:

CREATE TEMP SEQUENCE new_index;
SELECT SETVAL('new_index', 1);

并根据您的单位运行更新:

UPDATE assignment SET index=nextval('new_index') WHERE unit_id=35;

这将更新unit_id=35列上index上的所有行。

您的FROM子句有什么区别? nextval()为每一行执行一个函数,返回下一个序列号。

答案 3 :(得分:0)

由于您特别指出unit_id不是唯一的(“设置了单元35中的所有索引”),因此可以使用rownum()来投影每个intem的预期索引(如其他索引所示)。但是我也讨厌使用幻数,以下内容并不取决于它们。

with expectations as
     (select * 
        from (
              select unit_id
                   , unit_index
                   , row_number() over (partition by unit_id order by unit_id, unit_index) exp_index
                from units
            ) au
      where unit_index != exp_index
     )
update units u
   set unit_index = exp_index
  from expectations e
 where (u.unit_id, u.unit_index) = (e.unit_id,e.unit_index);

在此处查看fiddle