Postgres:批量更新查询以更新数组的指针?

时间:2018-04-18 11:31:46

标签: sql postgresql

目前在表中有这个:

+----+--------+--------------+------------------+
| id |  site  | location_ids | current_location |
+----+--------+--------------+------------------+
|  1 | google | [1,2,3]      |                2 |
|  2 | yahoo  | [2,3]        |                3 |
|  3 | reddit | [1]          |                1 |
|  4 | stack  | [1,2,4]      |                2 |
+----+--------+--------------+------------------+

我想要做的是批量更新查询,它会将当前位置更新为数组中的下一个项目,或者,如果我们已到达数组的末尾,则重置为第一个项目。

我目前正在手动执行此操作并在我的应用程序中构建逻辑:

update checks as chk set
  current_location = c.current_location
from (values
      (1, 3),
      (2, 2),
      (3, 1),
      (4, 4)
) as c(id, current_location)
where c.id = chk.id

3 个答案:

答案 0 :(得分:4)

其他海报使用的案例表达式可以用mod函数替换为稍短的解决方案:

%mod

的中缀版本
UPDATE checks
SET current_location = location_ids[
      array_position(location_ids, current_location) % cardinality(location_ids) + 1
]

答案 1 :(得分:2)

可能有一种更好的方式来编写它不涉及调用array_position两次,但是如果你使用PG 9.5(对于array_position函数)你可以这样做:

UPDATE your_table
SET current_location = location_ids[CASE WHEN array_length(location_ids, 1) = array_position(location_ids, current_location) THEN 1 ELSE array_position(location_ids, current_location) + 1 END];

因此它得到current_location的索引并检查它是否在数组的末尾。如果是,则获取索引1处的值(PG中的数组索引是从1开始的)。如果不是,则获得该位置的值+ 1。

答案 2 :(得分:2)

我假设Postgres 9.5或更高的答案:

您可以使用array_position(location_ids, current_location)找到当前位置ID的索引。下一个位置ID应该是下一个索引处的ID,除非该索引大于数组的长度。这可以放在一个表达式中:

case 
  when 
   array_position(location_ids, current_location) + 1 > cardinality(location_ids) 
     then 1 
   else array_position(location_ids, current_location) + 1 
end

此表达式可以直接用于更新语句:

update checks
   set current_location = 
        location_ids[case 
                      when array_position(location_ids, current_location) + 1 > cardinality(location_ids) 
                        then 1 
                      else array_position(location_ids, current_location) + 1 
                    end];