我有一个名为assignment
的表,其中包含index
和unit_id
列。一个单元中的每个作业都有一个唯一的索引。这样,单元中的分配可以通过交换索引来重新排序。
我正在尝试找出消除索引中潜在差距的最佳方法(例如,如果删除一行,索引将进入0
,1
,3
)。我当前的解决方案是以编程方式遍历单元中的每个分配,并在其索引与循环索引不匹配的情况下运行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
。为什么会这样?
答案 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。